'Copyright (C) 2009 Christiaan Cable
'
'This program is free software; you can redistribute it and/or
'modify it under the terms of the GNU General Public License
'as published by the Free Software Foundation; either version 3
'of the License, or (at your option) any later version.
'
'This program is distributed in the hope that it will be useful,
'but WITHOUT ANY WARRANTY; without even the implied warranty of
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'GNU General Public License for more details (LICENCE.TXT).

Imports System.Net
Imports System.IO
Imports System.Windows.Forms
Imports System.Management
Imports System.Security.Cryptography
Imports System.Text
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports TaskScheduler
Imports System.Xml
Imports OpenSmtp.Mail
Imports System.Globalization

Public Module Module1
    Private Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hwnd As Integer) As Integer
    Private Declare Function ReleaseDC Lib "user32" Alias "ReleaseDC" (ByVal hwnd As Integer, ByVal hdc As Integer) As Integer
    Private Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (ByVal hKey As Int32, ByVal lpSubKey As String, ByRef phkResult As Integer) As Integer
    Private Declare Function RegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Integer, ByVal lpValueName As String, ByVal Reserved As Integer, ByVal dwType As Integer, ByVal lpData As String, ByVal cbData As Integer) As Integer
    Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Integer) As Integer
    Private Const HKEY_LOCAL_MACHINE As Integer = &H80000002
    Private Const REG_QWORD As Integer = 11

    Private AppDataPath As String = GetAppDataPath()

    Private imgWarning As New Bitmap(GetType(Module1).Assembly.GetManifestResourceStream("UA.Warning.png"))

    Private RegularFont As Font
    Private BoldFont As Font
    Private StatsPosX As Integer
    Private FontHeight As Integer
    Public DebugISP As Boolean = True


    Function LoadPassword(ByVal strFileName As String) As String
        LoadPassword = Nothing
        Try
            If File.Exists(AppDataPath & strFileName) Then
                'read config
                Dim sr As New StreamReader(AppDataPath & strFileName)
                Dim Data As String = sr.ReadToEnd()
                sr.Close()

                'do de-obfuscation
                Dim myval As Integer
                Dim x, y As Integer

                'populate shift variables
                Dim Shift(20) As Integer
                ShiftIt(Shift)

                y = 0
                For x = 1 To Data.Length
                    y += 1
                    If y > 20 Then y = 1
                    myval = Asc(Mid(Data, x, 1))
                    myval -= Shift(y)
                    If myval > 128 Then myval -= 128
                    Mid(Data, x, 1) = Chr(myval)
                Next
                If Data <> "" Then LoadPassword = Data

            End If
        Catch ex As Exception
            LoadPassword = Nothing
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Function

    Sub SavePassword(ByVal strPassword As String, ByVal strFileName As String)
        Try
            If strPassword <> "" Then
                'do obfuscation
                Dim myval As Integer
                Dim x, y As Integer

                'populate shift variables
                Dim Shift(20) As Integer
                ShiftIt(Shift)

                Using sw As New StreamWriter(AppDataPath & strFileName)
                    y = 0
                    For x = 1 To strPassword.Length
                        y += 1
                        If y > 20 Then y = 1
                        myval = Asc(Mid(strPassword, x, 1))
                        myval += Shift(y)
                        If myval < 0 Then myval += 128
                        sw.Write(Chr(myval))
                    Next

                    sw.Close()
                End Using
            End If

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Public Sub ShiftIt(ByRef intShift() As Integer)
        intShift(0) = -13
        intShift(1) = -30
        intShift(2) = -26
        intShift(3) = -14
        intShift(4) = -6
        intShift(5) = -17
        intShift(6) = -4
        intShift(7) = -8
        intShift(8) = -3
        intShift(9) = -18
        intShift(10) = -7
        intShift(11) = -15
        intShift(12) = -16
        intShift(13) = -5
        intShift(14) = -11
        intShift(15) = -1
        intShift(16) = -9
        intShift(17) = -13
        intShift(18) = -25
        intShift(19) = -19
        intShift(20) = -2
    End Sub

    Sub WriteLog(ByVal ISPReturnData As ISPReturnData, ByVal bolRetrieveNICData As Boolean, ByVal NicUsageDown As Double, ByVal NicUsageUp As Double)
        'something wrong with nic data so ignore data
        If bolRetrieveNICData = True And (NicUsageDown = 0 Or NicUsageUp = 0) Then bolRetrieveNICData = False

        'dont do anything
        If ISPReturnData Is Nothing And bolRetrieveNICData = False Then Exit Sub

        '############################################

        Dim fsLog As IO.FileStream
        Dim wLog As IO.BinaryWriter
        Dim rLog As IO.BinaryReader

        Try
            'record structure (54 bytes)
            Dim LogDate As Integer                      '4 bytes
            Dim LogHour As Byte                         '1 byte
            Dim LogMinute As Byte                       '1 byte
            Dim LogSecond As Byte                       '1 byte
            Dim ISPDate As Integer                      '4 bytes
            Dim ISPHour As Byte                         '1 byte
            Dim ISPMinute As Byte                       '1 byte
            Dim ISPSecond As Byte                       '1 byte
            Dim ISPPeakDownload As Single               '4 bytes
            Dim ISPPeakUpload As Single                 '4 bytes
            Dim ISPOffpeakDownload As Single            '4 bytes
            Dim ISPOffpeakUpload As Single              '4 bytes
            Dim DownloadRaw As Double                   '8 bytes
            Dim UploadRaw As Double                     '8 bytes
            Dim DownloadChange As Single                '4 bytes
            Dim UploadChange As Single                  '4 bytes

            If Dir(AppDataPath & "usageagent.log", FileAttribute.Normal) <> "" Then
                'file exists so read last record
                fsLog = New IO.FileStream(AppDataPath & "usageagent.log", IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.ReadWrite)
                rLog = New IO.BinaryReader(fsLog)

                'jump to start of last record
                fsLog.Seek(-54, IO.SeekOrigin.End)

                'read data
                LogDate = rLog.ReadInt32
                LogHour = rLog.ReadByte
                LogMinute = rLog.ReadByte
                LogSecond = rLog.ReadByte
                ISPDate = rLog.ReadInt32
                ISPHour = rLog.ReadByte
                ISPMinute = rLog.ReadByte
                ISPSecond = rLog.ReadByte
                ISPPeakDownload = rLog.ReadSingle
                ISPPeakUpload = rLog.ReadSingle
                ISPOffpeakDownload = rLog.ReadSingle
                ISPOffpeakUpload = rLog.ReadSingle
                DownloadRaw = rLog.ReadDouble
                UploadRaw = rLog.ReadDouble
                DownloadChange = rLog.ReadSingle
                UploadChange = rLog.ReadSingle
                rLog.Close()
                fsLog.Close()

                If bolRetrieveNICData = True Then
                    'get last log date
                    Dim LastDate As Date = CDate(Microsoft.VisualBasic.Left(LogDate.ToString, 4) & "/" & Mid(LogDate.ToString, 5, 2) & "/" & Microsoft.VisualBasic.Right(LogDate.ToString, 2) & " " & Format(LogHour, "00") & ":" & Format(LogMinute, "00") & ":" & Format(LogSecond, "00"))

                    'get boot time
                    Dim upTime As New PerformanceCounter("System", "System Up Time")
                    'First call will always be zero!
                    upTime.NextValue()
                    Dim BootDate As Date = Now.AddSeconds(-upTime.NextValue)

                    'has computer been reset since the last entry?
                    If Date.Compare(LastDate, BootDate) < 0 Then
                        'yes
                        DownloadChange = CSng(Format((NicUsageDown) / 1024, "0.##"))
                        UploadChange = CSng(Format((NicUsageUp) / 1024, "0.##"))

                        'write reset time to log file
                        LogDate = CInt(Format(Now, "yyyyMMdd"))
                        LogHour = CByte(Format(Now, "HH"))
                        LogMinute = CByte(Format(Now, "mm"))
                        LogSecond = CByte(Format(Now, "ss"))

                        If ISPReturnData IsNot Nothing Then
                            'use new ISP values
                            ISPDate = CInt(Format(ISPReturnData.LastUpdated, "yyyyMMdd"))
                            ISPHour = CByte(Format(ISPReturnData.LastUpdated, "HH"))
                            ISPMinute = CByte(Format(ISPReturnData.LastUpdated, "mm"))
                            ISPSecond = CByte(Format(ISPReturnData.LastUpdated, "ss"))
                            ISPPeakDownload = ISPReturnData.PeakDownload
                            ISPPeakUpload = ISPReturnData.PeakUpload
                            ISPOffpeakDownload = ISPReturnData.OffpeakDownload
                            ISPOffpeakUpload = ISPReturnData.OffpeakUpload
                        End If
                        DownloadRaw = 0
                        UploadRaw = 0

                        SyncLock System.Threading.Thread.CurrentThread
                            'open log file
                            fsLog = New IO.FileStream(AppDataPath & "usageagent.log", IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
                            wLog = New IO.BinaryWriter(fsLog)

                            wLog.Write(LogDate)
                            wLog.Write(LogHour)
                            wLog.Write(LogMinute)
                            wLog.Write(LogSecond)
                            wLog.Write(ISPDate)
                            wLog.Write(ISPHour)
                            wLog.Write(ISPMinute)
                            wLog.Write(ISPSecond)
                            wLog.Write(ISPPeakDownload)
                            wLog.Write(ISPPeakUpload)
                            wLog.Write(ISPOffpeakDownload)
                            wLog.Write(ISPOffpeakUpload)
                            wLog.Write(DownloadRaw)
                            wLog.Write(UploadRaw)
                            wLog.Write(0)
                            wLog.Write(0)
                            wLog.Close()
                            fsLog.Close()
                        End SyncLock
                    Else
                        'no
                        If DownloadRaw > NicUsageDown Then
                            'counter reset has occured
                            DownloadChange = CSng(Format((NicUsageDown + (4294967295 - DownloadRaw)) / 1024, "0.##"))
                        Else
                            DownloadChange = CSng(Format((NicUsageDown - DownloadRaw) / 1024, "0.##"))
                        End If

                        If UploadRaw > NicUsageUp Then
                            'counter reset has occured
                            UploadChange = CSng(Format((NicUsageUp + (4294967295 - UploadRaw)) / 1024, "0.##"))
                        Else
                            UploadChange = CSng(Format((NicUsageUp - UploadRaw) / 1024, "0.##"))
                        End If
                    End If
                End If
            End If

            LogDate = CInt(Format(Now, "yyyyMMdd"))
            LogHour = CByte(Format(Now, "HH"))
            LogMinute = CByte(Format(Now, "mm"))
            LogSecond = CByte(Format(Now, "ss"))

            If ISPReturnData IsNot Nothing Then
                'use new ISP values
                ISPDate = CInt(Format(ISPReturnData.LastUpdated, "yyyyMMdd"))
                ISPHour = CByte(Format(ISPReturnData.LastUpdated, "HH"))
                ISPMinute = CByte(Format(ISPReturnData.LastUpdated, "mm"))
                ISPSecond = CByte(Format(ISPReturnData.LastUpdated, "ss"))
                ISPPeakDownload = ISPReturnData.PeakDownload
                ISPPeakUpload = ISPReturnData.PeakUpload
                ISPOffpeakDownload = ISPReturnData.OffpeakDownload
                ISPOffpeakUpload = ISPReturnData.OffpeakUpload
            End If

            DownloadRaw = NicUsageDown
            UploadRaw = NicUsageUp

            SyncLock System.Threading.Thread.CurrentThread
                'open log file
                fsLog = New IO.FileStream(AppDataPath & "usageagent.log", IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
                wLog = New IO.BinaryWriter(fsLog)

                wLog.Write(LogDate)
                wLog.Write(LogHour)
                wLog.Write(LogMinute)
                wLog.Write(LogSecond)
                wLog.Write(ISPDate)
                wLog.Write(ISPHour)
                wLog.Write(ISPMinute)
                wLog.Write(ISPSecond)
                wLog.Write(ISPPeakDownload)
                wLog.Write(ISPPeakUpload)
                wLog.Write(ISPOffpeakDownload)
                wLog.Write(ISPOffpeakUpload)
                wLog.Write(DownloadRaw)
                wLog.Write(UploadRaw)
                wLog.Write(DownloadChange)
                wLog.Write(UploadChange)
                wLog.Close()
                fsLog.Close()
            End SyncLock

        Catch ex1 As UnauthorizedAccessException

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Function ISPGet(ByVal strURL As String, ByVal CookieContainer As CookieContainer, ByVal ISPCredentials As ICredentials, Optional ByVal Referer As String = "") As String
        ISPGet = Nothing
        System.Net.ServicePointManager.CertificatePolicy = New TrustAllCertificatePolicy

        Dim webReq As HttpWebRequest = CType(WebRequest.Create(New Uri(strURL)), HttpWebRequest)
        webReq.CookieContainer = CookieContainer
        webReq.Credentials = ISPCredentials
        webReq.KeepAlive = True
        webReq.Timeout = 90000
        webReq.UserAgent = "UsageAgent"
        webReq.Method = "GET"
        webReq.ContentType = "text/html"
        webReq.AllowAutoRedirect = True
        If Referer <> "" Then webReq.Referer = Referer
        webReq.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-gb,en;q=0.5")

        Dim webResp As HttpWebResponse = CType(webReq.GetResponse, HttpWebResponse)
        Dim sr As New StreamReader(webResp.GetResponseStream)
        ISPGet = sr.ReadToEnd.Trim
        sr.Close()
        webResp.Close()
    End Function

    Function ISPPost(ByVal strURL As String, ByVal strPOSTData As String, ByVal CookieContainer As CookieContainer, ByVal ISPCredentials As ICredentials, Optional ByVal ContentType As String = "application/x-www-form-urlencoded", Optional ByVal Referer As String = "") As String
        ISPPost = Nothing
        System.Net.ServicePointManager.CertificatePolicy = New TrustAllCertificatePolicy

        Dim webReq As HttpWebRequest = CType(WebRequest.Create(New Uri(strURL)), HttpWebRequest)
        webReq.CookieContainer = CookieContainer
        webReq.Credentials = ISPCredentials
        webReq.KeepAlive = True
        webReq.Timeout = 90000
        webReq.UserAgent = "UsageAgent"
        webReq.Method = "POST"
        webReq.ContentType = ContentType
        webReq.ContentLength = strPOSTData.Length
        If Referer <> "" Then webReq.Referer = Referer
        webReq.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-gb,en;q=0.5")

        Dim sw As New StreamWriter(webReq.GetRequestStream)
        sw.Write(strPOSTData)
        sw.Close()

        Dim webResp As HttpWebResponse = CType(webReq.GetResponse, HttpWebResponse)
        Dim sr As New StreamReader(webResp.GetResponseStream)
        ISPPost = sr.ReadToEnd.Trim
        sr.Close()
        webResp.Close()
    End Function

    Function ExtractText(ByVal strSource As String, ByVal strSearch As String, ByVal intOffset As Integer, ByVal strStart As String, ByVal strEnd As String, Optional ByVal InstanceCount As Integer = 1) As String
        ExtractText = ""
        Dim x As Integer
        Dim Start As Integer = 1
        Dim Finish As Integer
        Dim Count As Integer = 0

        Do
            x = InStr(Start, strSource, strSearch, CompareMethod.Text)
            If x > 0 Then
                x += Len(strSearch) + intOffset
                Start = InStr(x, strSource, strStart, CompareMethod.Text)
                If Start > 0 Then
                    Start = Start + Len(strStart)
                    Finish = InStr(Start, strSource, strEnd, CompareMethod.Text)
                    If Finish > 0 Then
                        ExtractText = Mid(strSource, Start, Finish - Start)
                    End If
                End If
                Start = Finish + Len(strEnd)
                If Start > Len(strSource) + 1 Then Exit Do
                Count += 1
                If Count = InstanceCount Then Exit Do
            Else
                Exit Do
            End If
        Loop

    End Function

    Sub ComboAddISP(ByVal cboISP As ComboBox)
        'add ISP's
        cboISP.Items.Clear()
        cboISP.Items.Add(New ISP("", ""))
        cboISP.Items.Add(New ISP("aaNet", "https://www.aanet.com.au/members.html"))
        cboISP.Items.Add(New ISP("AAPT", "https://dialup.connect.com.au/cgi-bin/subscribers/usagepd.cgi"))
        cboISP.Items.Add(New ISP("AAPT New", "https://dialup.connect.com.au/cgi-bin/subscribers/usagepd.cgi"))
        cboISP.Items.Add(New ISP("Adam", "http://www.adam.com.au/"))
        cboISP.Items.Add(New ISP("amnet", "http://www.amcom.com.au/default.aspx?MenuID=109"))
        cboISP.Items.Add(New ISP("BettaMomentum", "http://tarka.momentuminternet.com.au/custdata"))
        cboISP.Items.Add(New ISP("Blitz", "https://members.koalatelecom.com.au/broadband/custusage"))
        cboISP.Items.Add(New ISP("Cirrus", "https://cms.cirruscomms.com.au/custdata/customer-view.php3"))
        cboISP.Items.Add(New ISP("ComCen", "https://lounge.comcen.com.au/"))
        cboISP.Items.Add(New ISP("dodo", "http://home.dodo.com.au/members_home.asp"))
        cboISP.Items.Add(New ISP("EFTel", "https://myaccount.eftel.com/MyAccount/Security/SignOn.aspx"))
        cboISP.Items.Add(New ISP("Exetel", "https://www.exetel.com.au/members/"))
        cboISP.Items.Add(New ISP("Exetel Wireless", "https://www.exetel.com.au/wireless_login/"))
        cboISP.Items.Add(New ISP("G-node", "https://www.g-node.com.au/index.asp"))
        ''cboISP.Items.Add(New ISP("iiNet", "https://toolbox.iinet.net.au/"))
        cboISP.Items.Add(New ISP("Internode", "https://accounts.internode.on.net/cgi-bin/login"))
        cboISP.Items.Add(New ISP("iSage", "https://www.isage.net.au/members/index.php"))
        cboISP.Items.Add(New ISP("G-node", "https://www.g-node.com.au/index.asp"))
        cboISP.Items.Add(New ISP("Netspace", "https://my.netspace.net.au/logincheck"))
        cboISP.Items.Add(New ISP("OntheNet", "http://support.onthenet.com.au/displayitem.asp?ID=26"))
        cboISP.Items.Add(New ISP("Optus", "https://memberservices.optuszoo.com.au/login/?target=/myusage/"))
        cboISP.Items.Add(New ISP("Primus", "https://toolbox.iprimus.com.au/FormsLogin.asp?/"))
        cboISP.Items.Add(New ISP("Soul", "https://www.mysoul.com.au/bweb/html/duismail/duismail.html"))
        cboISP.Items.Add(New ISP("Spin", "https://my.spin.net.au"))
        cboISP.Items.Add(New ISP("SuperNerd", "https://www.supernerd.com.au/members.htm"))
        cboISP.Items.Add(New ISP("Telstra", "https://www.bigpond.com/mybigpond/default.asp"))
        cboISP.Items.Add(New ISP("TPG", "https://cyberstore.tpg.com.au/your_account/"))
        cboISP.Items.Add(New ISP("Webshield", "http://webshield.net.au/main.htm"))
        cboISP.Items.Add(New ISP("Westnet", "https://myaccount.westnet.com.au/Login.aspx?ReturnUrl=%2fDefault.aspx"))
    End Sub

    Function GetISPHomePage(ByVal strISPName As String) As String
        GetISPHomePage = ""
        Dim cboISP As New ComboBox
        ComboAddISP(cboISP)
        For Each NewISP As ISP In cboISP.Items
            If NewISP.Name = strISPName Then
                GetISPHomePage = NewISP.HomePage
                Exit For
            End If
        Next
        cboISP.Dispose()

    End Function

    Sub DisableControlChildren(ByVal NewControl As Control)
        Dim NewControl1 As Control
        For Each NewControl1 In NewControl.Controls
            If NewControl1.GetType Is GetType(GroupBox) Then
                NewControl1.Enabled = False
                'parent control
                DisableControlChildren(NewControl1)
            ElseIf NewControl1.GetType Is GetType(TextBox) Or NewControl1.GetType Is GetType(ComboBox) Or NewControl1.GetType Is GetType(ListBox) Or NewControl1.GetType Is GetType(Button) Or NewControl1.GetType Is GetType(RadioButton) Or NewControl1.GetType Is GetType(Label) Or NewControl1.GetType Is GetType(CheckBox) Then
                'child control
                NewControl1.Enabled = False
            End If
        Next
    End Sub

    Sub EnableControlChildren(ByVal NewControl As Control)
        Dim NewControl1 As Control
        For Each NewControl1 In NewControl.Controls
            If NewControl1.GetType Is GetType(GroupBox) Then
                NewControl1.Enabled = True
                'parent control
                EnableControlChildren(NewControl1)
            ElseIf NewControl1.GetType Is GetType(TextBox) Or NewControl1.GetType Is GetType(ComboBox) Or NewControl1.GetType Is GetType(ListBox) Or NewControl1.GetType Is GetType(Button) Or NewControl1.GetType Is GetType(RadioButton) Or NewControl1.GetType Is GetType(Label) Or NewControl1.GetType Is GetType(CheckBox) Then
                'child control
                NewControl1.Enabled = True
            End If
        Next
    End Sub

    Function UnixDetected() As Boolean
        If Environment.OSVersion.Platform = 4 Or Environment.OSVersion.Platform = 128 Then
            UnixDetected = True
        Else
            UnixDetected = False
        End If
    End Function

    Function VistaDetected() As Boolean
        If Environment.OSVersion.Platform = 2 And Environment.OSVersion.Version.Major = 6 Then
            VistaDetected = True
        Else
            VistaDetected = False
        End If
    End Function

    Sub RegEnablePerfCounter()
        'enable tcp performance if currently disabled
        Dim RegKey As Microsoft.Win32.RegistryKey = Nothing
        Try
            'get the tcp performance key
            RegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Services\Tcpip\Performance", True)
            If Not (RegKey) Is Nothing Then
                Dim KeyValue As String = Format(RegKey.GetValue("Disable Performance Counters"))

                'if tcp is disabled, try enabling it by writing back a value of 0
                If KeyValue = "1" Then
                    RegKey.SetValue("Disable Performance Counters", &H0)

                    'reset application
                    MessageBox.Show("The TCP Performance counter has been enabled. Please restart Usage Agent", "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    Exit Sub
                End If
            End If
        Catch ex As Exception
        Finally
            If Not (RegKey) Is Nothing Then RegKey.Close()
        End Try

        'enable PerfOS performance if currently disabled
        Try
            'get the PerfOS performance key
            RegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Services\PerfOS\Performance", True)

            If Not (RegKey) Is Nothing Then
                Dim KeyValue As String = Format(RegKey.GetValue("Disable Performance Counters"))

                'if PerfOS is disabled, try enabling it by writing back a value of 0
                If KeyValue = "1" Then
                    RegKey.SetValue("Disable Performance Counters", &H0)

                    'reset application
                    MessageBox.Show("The PerfOS Performance counter has been enabled. Please restart Usage Agent", "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    Exit Sub
                End If
            End If
        Catch ex As Exception
        Finally
            If Not (RegKey) Is Nothing Then RegKey.Close()
        End Try

    End Sub

    Sub SetDefaultUsageColourValue(ByVal lstUsageColourValue As ListBox)
        lstUsageColourValue.Items.Clear()
        'Green >0
        lstUsageColourValue.Items.Add(New UsageColourValue(0, "-16730368"))
        'yellow  >= 50
        lstUsageColourValue.Items.Add(New UsageColourValue(50, "-256"))
        'red >= 90
        lstUsageColourValue.Items.Add(New UsageColourValue(90, "-65536"))
        lstUsageColourValue.Items.Add(New UsageColourValue(100, "-65536"))
    End Sub

    Function GetCPUID() As String
        GetCPUID = ""
        Try

            If UnixDetected() = False Then
                Dim moReturn As Management.ManagementObjectCollection
                Dim moSearch As Management.ManagementObjectSearcher
                Dim mo As Management.ManagementObject
                moSearch = New Management.ManagementObjectSearcher("Select * from Win32_Processor")
                moReturn = moSearch.Get
                For Each mo In moReturn
                    GetCPUID = Format(mo("ProcessorID"))
                    Exit For
                Next
            Else
                'OBFUSCATE
                GetCPUID = "0DFA2CFFBBD3"
            End If

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Function

    Sub SetProxyServer(ByVal strProxyName As String, ByVal strProxyPort As String, ByVal strProxyLogin As String, ByVal strProxyPassword As String)
        If strProxyName.StartsWith("http://") = False Then strProxyName = "http://" & strProxyName
        Dim NewWebProxy As New WebProxy(strProxyName & ":" & strProxyPort, True)
        If strProxyLogin = "" And strProxyPassword = "" Then
            'use the default windows credentials
            NewWebProxy.Credentials = System.Net.CredentialCache.DefaultCredentials
        Else
            NewWebProxy.Credentials = New System.Net.NetworkCredential(strProxyLogin, strProxyPassword)
        End If

        WebRequest.DefaultWebProxy = NewWebProxy
    End Sub

    Function GetDPI() As Single
        If UnixDetected() = False Then
            Dim hdcSrc As System.IntPtr = CType(GetDC(0), System.IntPtr)
            Dim dpix As Single = Graphics.FromHdc(hdcSrc).DpiX
            ReleaseDC(0, CType(hdcSrc, Integer))
            Return dpix
        Else
            Return 96
        End If
    End Function

    Sub DrawISPGraph(ByVal TargetBitmap As Bitmap, ByVal YOffset As Integer, ByVal ISPReturnData As ISPReturnData, ByVal IconISPUsageColourValue As ListBox, ByVal ShowBackground As Boolean, ByVal ForeColour As Color)

        Dim g As Graphics = Graphics.FromImage(TargetBitmap)

        'ISP graphs
        Dim XOffset As Integer

        YOffset += 3
        Dim NewValue As Integer
        For Each NewGraphItem As GraphItem In ISPReturnData.GraphItemList
            'draw indicator
            If NewGraphItem.DrawIndicator = True Then
                DrawRoundedRectangle(g, 2, YOffset - 1, CInt(TargetBitmap.Width - 5), FontHeight + 6, Color.Yellow, True, True)
            End If

            'draw graph
            If NewGraphItem.MaxValue >= 1 Then
                NewValue = CInt((NewGraphItem.Value / NewGraphItem.MaxValue) * (TargetBitmap.Width - 8))
            Else
                NewValue = 0
            End If
            DrawGraph(IconISPUsageColourValue, g, 3, YOffset, NewValue, CInt(TargetBitmap.Width - 7))

            'draw label
            XOffset = CInt((-g.MeasureString(NewGraphItem.Label, BoldFont, 1000, StringFormat.GenericTypographic).Width / 2) + 5)
            g.ResetTransform()
            g.TranslateTransform(CSng(TargetBitmap.Width / 2), 4, Drawing.Drawing2D.MatrixOrder.Append)
            DrawOutlinedText(ShowBackground, ForeColour, g, NewGraphItem.Label, BoldFont, XOffset, YOffset - 2, True)

            YOffset += FontHeight + 6
        Next

        g.ResetTransform()

        g.Dispose()
    End Sub

    Sub DrawGraph(ByVal IconISPUsageColourValue As ListBox, ByVal g As Graphics, ByVal intPosX As Integer, ByVal intPosY As Integer, ByVal intValue As Integer, ByVal intMaxValue As Integer)
        Dim intHeight As Integer = FontHeight + 4

        'dont go over 100%
        intValue += 1
        If intValue > intMaxValue Then intValue = intMaxValue

        'draw background
        DrawRoundedRectangle(g, intPosX, intPosY, intMaxValue, intHeight, Color.Black, True, True)

        g.ResetTransform()
        Dim gp As New Drawing2D.GraphicsPath
        gp.StartFigure()

        If intValue >= 12 Then
            'top line
            gp.AddLine(intPosX + 6, intPosY, intPosX + intValue - 6, intPosY)

            'top right curve
            gp.AddLine(intPosX + intValue - 5, intPosY + 1, intPosX + intValue - 4, intPosY + 1)
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)
            gp.AddLine(intPosX + intValue - 4, intPosY + intHeight - 1, intPosX + intValue - 5, intPosY + intHeight - 1)

            'bottom line
            gp.AddLine(intPosX + intValue - 6, intPosY + intHeight, intPosX + 6, intPosY + intHeight)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue >= 9 Then
            'top right curve
            gp.AddLine(intPosX + intValue - 5, intPosY + 1, intPosX + intValue - 4, intPosY + 1)
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)
            gp.AddLine(intPosX + intValue - 4, intPosY + intHeight - 1, intPosX + intValue - 5, intPosY + intHeight - 1)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue = 8 Then
            'top right curve
            gp.AddLine(intPosX + intValue - 4, intPosY + 1, intPosX + intValue - 4, intPosY + 1)
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)
            gp.AddLine(intPosX + intValue - 4, intPosY + intHeight - 1, intPosX + intValue - 4, intPosY + intHeight - 1)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue = 7 Then
            'top right curve
            gp.AddLine(intPosX + intValue - 4, intPosY + 2, intPosX + intValue - 3, intPosY + 2)
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)
            gp.AddLine(intPosX + intValue - 3, intPosY + intHeight - 2, intPosX + intValue - 4, intPosY + intHeight - 2)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue = 6 Then
            'top right curve
            gp.AddLine(intPosX + intValue - 3, intPosY + 2, intPosX + intValue - 3, intPosY + 2)
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)
            gp.AddLine(intPosX + intValue - 3, intPosY + intHeight - 2, intPosX + intValue - 3, intPosY + intHeight - 2)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue = 5 Then
            'top right curve
            gp.AddLine(intPosX + intValue - 3, intPosY + 3, intPosX + intValue - 3, intPosY + 3)
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)
            gp.AddLine(intPosX + intValue - 3, intPosY + intHeight - 3, intPosX + intValue - 3, intPosY + intHeight - 3)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue = 4 Then
            'top right curve
            gp.AddLine(intPosX + intValue - 2, intPosY + 3, intPosX + intValue - 2, intPosY + 3)
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)
            gp.AddLine(intPosX + intValue - 2, intPosY + intHeight - 3, intPosX + intValue - 2, intPosY + intHeight - 3)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue >= 2 Then
            'top right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + 4, intPosX + intValue - 1, intPosY + 5)

            'right line
            gp.AddLine(intPosX + intValue, intPosY + 6, intPosX + intValue, intPosY + intHeight - 6)

            'bottom right curve
            gp.AddLine(intPosX + intValue - 1, intPosY + intHeight - 5, intPosX + intValue - 1, intPosY + intHeight - 4)

            'bottom Left curve
            gp.AddLine(intPosX + 5, intPosY + intHeight - 1, intPosX + 4, intPosY + intHeight - 1)
            gp.AddLine(intPosX + 1, intPosY + intHeight - 4, intPosX + 1, intPosY + intHeight - 5)

            'Left line
            gp.AddLine(intPosX, intPosY + intHeight - 6, intPosX, intPosY + 6)

            'top Left curve
            gp.AddLine(intPosX + 1, intPosY + 5, intPosX + 1, intPosY + 4)
            gp.AddLine(intPosX + 4, intPosY + 1, intPosX + 5, intPosY + 1)

            gp.CloseFigure()
        ElseIf intValue = 1 Then
            'do nothing
        End If

        'set colour
        Dim StartPoint As New Point(1, 1)
        Dim EndPoint As New Point(intMaxValue + 3, 1)

        'initialise colours array
        Dim myColors(IconISPUsageColourValue.Items.Count + 1) As Color
        Dim myPositions(IconISPUsageColourValue.Items.Count + 1) As Single
        Dim x As Integer
        For Each NewUsageColourValue As UsageColourValue In IconISPUsageColourValue.Items
            'set first value to 0 if not already so
            If x = 0 And NewUsageColourValue.Percentage <> 0 Then
                myColors(x) = Color.FromArgb(CInt(NewUsageColourValue.Value))
                myPositions(x) = 0
                x += 1
            End If
            myColors(x) = Color.FromArgb(CInt(NewUsageColourValue.Value))
            myPositions(x) = CSng(NewUsageColourValue.Percentage / 100)
            x += 1
        Next
        'set last value to 1 if not already so
        If myPositions(x - 1) <> 1 Then
            myColors(x) = myColors(x - 1)
            myPositions(x) = 1
            x += 1
        End If
        'resize array
        ReDim Preserve myColors(x - 1)
        ReDim Preserve myPositions(x - 1)

        Dim myBlend As New System.Drawing.Drawing2D.ColorBlend
        myBlend.Colors = myColors
        myBlend.Positions = myPositions
        Dim lgBrush As New System.Drawing.Drawing2D.LinearGradientBrush(StartPoint, EndPoint, Color.Green, Color.Red)

        lgBrush.InterpolationColors = myBlend

        g.FillPath(lgBrush, gp)
        g.DrawPath(Pens.Black, gp)
        gp.Dispose()

        '##########################################################3

        'add fade effect
        g.DrawLine(New Pen(Color.FromArgb(100, 0, 0, 0)), intPosX + 5, intPosY + 1, intPosX + intMaxValue - 5, intPosY + 1)
        g.DrawLine(New Pen(Color.FromArgb(80, 0, 0, 0)), intPosX + 3, intPosY + 2, intPosX + intMaxValue - 3, intPosY + 2)
        g.DrawLine(New Pen(Color.FromArgb(60, 0, 0, 0)), intPosX + 2, intPosY + 3, intPosX + intMaxValue - 2, intPosY + 3)
        g.DrawLine(New Pen(Color.FromArgb(30, 0, 0, 0)), intPosX + 1, intPosY + 4, intPosX + intMaxValue - 1, intPosY + 4)
        g.DrawLine(New Pen(Color.FromArgb(15, 0, 0, 0)), intPosX, intPosY + 5, intPosX + intMaxValue, intPosY + 5)
        g.DrawLine(New Pen(Color.FromArgb(7, 0, 0, 0)), intPosX, intPosY + 6, intPosX + intMaxValue, intPosY + 6)

        'g.DrawLine(New Pen(Color.FromArgb(0, 0, 0, 0)), intPosX, intPosY + 7, intPosX + intMaxValue, intPosY + 7)

        g.DrawLine(New Pen(Color.FromArgb(7, 0, 0, 0)), intPosX, intPosY + intHeight - 6, intPosX + intMaxValue, intPosY + intHeight - 6)
        g.DrawLine(New Pen(Color.FromArgb(15, 0, 0, 0)), intPosX, intPosY + intHeight - 5, intPosX + intMaxValue, intPosY + intHeight - 5)
        g.DrawLine(New Pen(Color.FromArgb(30, 0, 0, 0)), intPosX + 1, intPosY + intHeight - 4, intPosX + intMaxValue - 1, intPosY + intHeight - 4)
        g.DrawLine(New Pen(Color.FromArgb(60, 0, 0, 0)), intPosX + 2, intPosY + intHeight - 3, intPosX + intMaxValue - 2, intPosY + intHeight - 3)
        g.DrawLine(New Pen(Color.FromArgb(80, 0, 0, 0)), intPosX + 3, intPosY + intHeight - 2, intPosX + intMaxValue - 3, intPosY + intHeight - 2)
        g.DrawLine(New Pen(Color.FromArgb(100, 0, 0, 0)), intPosX + 5, intPosY + intHeight - 1, intPosX + intMaxValue - 4, intPosY + intHeight - 1)

    End Sub

    Sub DrawISPStats(ByVal g As Graphics, ByVal YOffset As Integer, ByVal NewConfigurationData As ConfigurationData, ByVal ISPReturnData As ISPReturnData)
        Dim NewForeColor As Color = Color.FromArgb(CInt(NewConfigurationData.ForeColour))

        For Each NewTextItem As TextItem In ISPReturnData.TextItemList
            DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, NewTextItem.Label, RegularFont, 5, YOffset)
            DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, NewTextItem.Data, BoldFont, StatsPosX, YOffset)
            YOffset += FontHeight
        Next
    End Sub

    Sub DrawNICStats(ByVal g As Graphics, ByVal YOffset As Integer, ByVal NewConfigurationData As ConfigurationData, ByVal ISPReturnData As ISPReturnData, ByVal SumDownloadChange As Double, ByVal SumUploadChange As Double, ByVal SumOffpeakDownloadChange As Double, ByVal SumOffpeakUploadChange As Double)
        Dim NewForeColor As Color = Color.FromArgb(CInt(NewConfigurationData.ForeColour))

        If Val(NewConfigurationData.OffpeakStartHour) <> 0 Or Val(NewConfigurationData.OffpeakEndHour) <> 0 Then
            If NewConfigurationData.WAIXAvailable = True Then
                'waix
                'nic peak d/l
                YOffset += 3
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Peak D/L :", RegularFont, 5, YOffset)
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumDownloadChange + SumOffpeakDownloadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)

                'nic peak u/l
                YOffset += FontHeight
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Peak U/L :", RegularFont, 5, YOffset)
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumUploadChange + SumOffpeakUploadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)
            Else
                'offpeak
                'nic peak d/l
                YOffset += 3
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Peak D/L :", RegularFont, 5, YOffset)
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumDownloadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)

                'nic peak u/l
                YOffset += FontHeight
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Peak U/L :", RegularFont, 5, YOffset)
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumUploadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)

                'nic offpeak d/l
                YOffset += FontHeight
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Offpeak D/L :", RegularFont, 5, YOffset)
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumOffpeakDownloadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)

                'nic offpeak u/l
                YOffset += FontHeight
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Offpeak U/L :", RegularFont, 5, YOffset)
                DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumOffpeakUploadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)
            End If
        Else
            'nic peak d/l
            YOffset += 3
            DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Peak D/L :", RegularFont, 5, YOffset)
            DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumDownloadChange + SumOffpeakDownloadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)

            'nic peak u/l
            YOffset += FontHeight
            DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, "NIC Peak U/L :", RegularFont, 5, YOffset)
            DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, Format(SumUploadChange + SumOffpeakUploadChange, "#0.0 MB"), BoldFont, StatsPosX, YOffset)
        End If

    End Sub

    Sub RetrieveNICData(ByVal ISPReturnData As ISPReturnData, ByRef SumDownloadChange As Double, ByRef SumUploadChange As Double, ByRef SumOffpeakDownloadChange As Double, ByRef SumOffpeakUploadChange As Double)
        Try
            Dim LogDate As Integer
            Dim LogHour As Integer
            Dim SelectedDate As Integer = CInt(Format(Now, "yyyyMM01"))

            If Dir(AppDataPath & "usageagent.log", FileAttribute.Normal) <> "" Then
                Dim fsLog As IO.FileStream
                Dim rLog As IO.BinaryReader

                fsLog = New IO.FileStream(AppDataPath & "usageagent.log", IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.ReadWrite)
                rLog = New IO.BinaryReader(fsLog)

                'loop through file 
                While fsLog.Position < fsLog.Length
                    'get record date
                    LogDate = rLog.ReadInt32
                    LogHour = rLog.ReadByte
                    'look for where LogDate >= 1st of this month
                    If LogDate >= SelectedDate Then
                        'skip to start of next field
                        fsLog.Seek(41, IO.SeekOrigin.Current)

                        If ISPReturnData IsNot Nothing Then
                            'check if we are in peak or off peak time
                            If ISPReturnData.OffpeakNow = True Then
                                'offpeak
                                'total downloads in MB
                                SumOffpeakDownloadChange += rLog.ReadSingle / 1024
                                'total uploads in MB
                                SumOffpeakUploadChange += rLog.ReadSingle / 1024
                            Else
                                'peak
                                'total downloads in MB
                                SumDownloadChange += rLog.ReadSingle / 1024
                                'total uploads in MB
                                SumUploadChange += rLog.ReadSingle / 1024
                            End If
                        Else
                            'peak
                            'total downloads in MB
                            SumDownloadChange += rLog.ReadSingle / 1024
                            'total uploads in MB
                            SumUploadChange += rLog.ReadSingle / 1024
                        End If
                    Else
                        'skip to start of next record
                        fsLog.Seek(49, IO.SeekOrigin.Current)
                    End If
                End While

                rLog.Close()
                fsLog.Close()
            End If

        Catch ex1 As UnauthorizedAccessException

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try

    End Sub

    Sub DrawOutlinedText(ByVal bolShowBackgroundColour As Boolean, ByVal ForegroundColour As Color, ByVal g As Graphics, ByVal strText As String, ByVal myFont As Font, ByVal X As Integer, ByVal Y As Integer, Optional ByVal bolGraphText As Boolean = False)
        'set colour
        Dim myBrush As New SolidBrush(Color.Black)

        g.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit

        If bolShowBackgroundColour = False Or bolGraphText = True Then
            g.DrawString(strText, myFont, myBrush, X - 1, Y, StringFormat.GenericTypographic)
            g.DrawString(strText, myFont, myBrush, X - 1, Y - 1, StringFormat.GenericTypographic)
            g.DrawString(strText, myFont, myBrush, X - 1, Y + 1, StringFormat.GenericTypographic)
            g.DrawString(strText, myFont, myBrush, X, Y - 1, StringFormat.GenericTypographic)
            g.DrawString(strText, myFont, myBrush, X, Y + 1, StringFormat.GenericTypographic)
            g.DrawString(strText, myFont, myBrush, X + 1, Y + 1, StringFormat.GenericTypographic)
            g.DrawString(strText, myFont, myBrush, X + 1, Y, StringFormat.GenericTypographic)
            g.DrawString(strText, myFont, myBrush, X + 1, Y - 1, StringFormat.GenericTypographic)
        End If

        'set colour
        myBrush = New SolidBrush(ForegroundColour)
        g.DrawString(strText, myFont, myBrush, X, Y, StringFormat.GenericTypographic)

        ''clean up
        myBrush.Dispose()

        g.ResetTransform()
    End Sub

    Sub DrawRoundedRectangle(ByVal g As Graphics, ByVal intPosX As Integer, ByVal intPosY As Integer, ByVal intWidth As Integer, ByVal intHeight As Integer, ByVal colColor As Color, ByVal bolShowTopCurve As Boolean, ByVal bolShowBottomCurve As Boolean)
        g.ResetTransform()

        Dim gp As New Drawing2D.GraphicsPath
        gp.StartFigure()

        If bolShowTopCurve = True Then
            'top Left curve
            Dim NewCurve4() As Point = {New Point(intPosX, intPosY + 5), New Point(intPosX + 2, intPosY + 2), New Point(intPosX + 5, intPosY)}
            gp.AddCurve(NewCurve4)

            'top line
            gp.AddLine(intPosX + 5, intPosY, intPosX + intWidth - 5, intPosY)

            'top right curve
            Dim NewCurve1() As Point = {New Point(intPosX + intWidth - 5, intPosY), New Point(intPosX + intWidth - 2, intPosY + 2), New Point(intPosX + intWidth, intPosY + 5)}
            gp.AddCurve(NewCurve1)
        Else
            gp.AddLine(intPosX, intPosY + 5, intPosX, intPosY)
            gp.AddLine(intPosX, intPosY, intPosX + intWidth, intPosY)
            gp.AddLine(intPosX + intWidth, intPosY, intPosX + intWidth, intPosY + 5)
        End If

        'right line
        gp.AddLine(intPosX + intWidth, intPosY + 5, intPosX + intWidth, intPosY + intHeight - 5)

        If bolShowBottomCurve = True Then
            'bottom right curve
            Dim NewCurve2() As Point = {New Point(intPosX + intWidth, intPosY + intHeight - 5), New Point(intPosX + intWidth - 2, intPosY + intHeight - 2), New Point(intPosX + intWidth - 5, intPosY + intHeight)}
            gp.AddCurve(NewCurve2)

            'bottom line
            gp.AddLine(intPosX + intWidth - 5, intPosY + intHeight, intPosX + 5, intPosY + intHeight)

            'bottom Left curve
            Dim NewCurve3() As Point = {New Point(intPosX + 5, intPosY + intHeight), New Point(intPosX + 2, intPosY + intHeight - 2), New Point(intPosX, intPosY + intHeight - 5)}
            gp.AddCurve(NewCurve3)
        Else
            gp.AddLine(intPosX + intWidth, intPosY + intHeight - 5, intPosX + intWidth, intPosY + intHeight)
            gp.AddLine(intPosX + intWidth, intPosY + intHeight, intPosX, intPosY + intHeight)
            gp.AddLine(intPosX, intPosY + intHeight, intPosX, intPosY + intHeight - 5)
        End If

        'Left line
        gp.AddLine(intPosX, intPosY + intHeight - 5, intPosX, intPosY + 5)

        gp.CloseFigure()
        g.SmoothingMode = SmoothingMode.None
        g.FillPath(New SolidBrush(colColor), gp)
        g.DrawPath(New Pen(colColor), gp)
        gp.Dispose()
    End Sub

    Sub ExportTextLog(ByVal ISPReturnData As ISPReturnData, ByVal FormData As ConfigurationData)
        Try
            'export usage data to a text file
            Dim ExportPath As String = FormData.ExportPath
            If ExportPath.EndsWith(Path.DirectorySeparatorChar) = False Then ExportPath &= Path.DirectorySeparatorChar

            Using sw As New StreamWriter(ExportPath & "isp.txt")
                Dim strMB As String = ""
                If FormData.ExportNotations = True Then strMB = " MB"

                If FormData.ExportDescriptors = True Then
                    If FormData.ExportDownload = True Then
                        sw.WriteLine("Peak Download: " & ISPReturnData.PeakDownload & strMB)
                        If FormData.OffpeakAvailable = True Then sw.WriteLine("Offpeak Download: " & ISPReturnData.OffpeakDownload & strMB)
                    End If
                    If FormData.ExportRemaining = True Then
                        sw.WriteLine("Peak Download Remaining: " & ISPReturnData.PeakUsageRemainingDescription)
                        If FormData.OffpeakAvailable = True Then sw.WriteLine("Offpeak Download Remaining: " & ISPReturnData.OffpeakUsageRemainingDescription)
                    End If
                    If FormData.ExportAverage = True Then
                        sw.WriteLine("Peak Average Download: " & ISPReturnData.PeakUsageAverageDescription)
                        If FormData.OffpeakAvailable = True Then sw.WriteLine("Offpeak Average Download: " & ISPReturnData.OffpeakUsageAverageDescription)
                    End If
                    If FormData.ExportAverageRemaining = True Then
                        sw.WriteLine("Peak Average Download Remaining: " & ISPReturnData.PeakUsageRemainingPerDayDescription)
                        If FormData.OffpeakAvailable = True Then sw.WriteLine("Offpeak Average Download Remaining: " & ISPReturnData.OffpeakUsageRemainingPerDayDescription)
                    End If
                    If FormData.ExportPlanLimit = True Then
                        sw.WriteLine("Peak Plan Limit: " & FormData.PeakUsageLimit & strMB)
                        If FormData.OffpeakAvailable = True Then sw.WriteLine("Offpeak Plan Limit: " & FormData.OffpeakUsageLimit & strMB)
                    End If
                    If FormData.ExportShaped = True Then sw.WriteLine("Account Shaped: " & ISPReturnData.ShapedNow.ToString)
                    If FormData.ExportTime = True Then sw.WriteLine("ISP Update Time: " & ISPReturnData.LastUpdated.ToString)
                    If FormData.ExportUpload = True Then
                        sw.WriteLine("Peak Upload: " & ISPReturnData.PeakUpload.ToString & strMB)
                        If FormData.OffpeakAvailable = True Then sw.WriteLine("Offpeak Upload: " & ISPReturnData.OffpeakUpload.ToString & strMB)
                    Else
                        If FormData.ExportDownload = True Then
                            sw.WriteLine(ISPReturnData.PeakDownload & strMB)
                            If FormData.OffpeakAvailable = True Then sw.WriteLine(ISPReturnData.OffpeakDownload & strMB)
                        End If
                        If FormData.ExportRemaining = True Then
                            sw.WriteLine(ISPReturnData.PeakUsageRemainingDescription)
                            If FormData.OffpeakAvailable = True Then sw.WriteLine(ISPReturnData.OffpeakUsageRemainingDescription)
                        End If
                        If FormData.ExportAverage = True Then
                            sw.WriteLine(ISPReturnData.PeakUsageAverageDescription)
                            If FormData.OffpeakAvailable = True Then sw.WriteLine(ISPReturnData.OffpeakUsageAverageDescription)
                        End If
                        If FormData.ExportAverageRemaining = True Then
                            sw.WriteLine(ISPReturnData.PeakUsageRemainingPerDayDescription)
                            If FormData.OffpeakAvailable = True Then sw.WriteLine(ISPReturnData.OffpeakUsageRemainingPerDayDescription)
                        End If
                        If FormData.ExportPlanLimit = True Then
                            sw.WriteLine(FormData.PeakUsageLimit & strMB)
                            If FormData.OffpeakAvailable = True Then sw.WriteLine(FormData.OffpeakUsageLimit & strMB)
                        End If
                        If FormData.ExportShaped = True Then sw.WriteLine(ISPReturnData.ShapedNow.ToString)
                        If FormData.ExportTime = True Then sw.WriteLine(ISPReturnData.LastUpdated.ToString)
                        If FormData.ExportUpload = True Then
                            sw.WriteLine(ISPReturnData.PeakUpload.ToString & strMB)
                            If FormData.OffpeakAvailable = True Then sw.WriteLine(ISPReturnData.OffpeakUpload.ToString & strMB)
                        End If
                    End If
                End If
                sw.Close()
            End Using
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try

    End Sub

    Function CalculateFormSize(ByVal NewConfigurationData As ConfigurationData, ByVal ISPReturnData As ISPReturnData) As Point

        'calc width
        Dim TempBitmap As New Bitmap(1, 1)
        Dim g As Graphics = Graphics.FromImage(TempBitmap)
        Dim FormWidth As Integer = CInt(g.MeasureString("Offpeak Avg. Left : 8888 MB/Day (30 Days)", BoldFont, 1000, StringFormat.GenericTypographic).Width) + 4
        FontHeight = CInt(g.MeasureString("O", BoldFont, 1000, StringFormat.GenericTypographic).Height)
        TempBitmap.Dispose()

        '#######################################################################3

        'calc height
        Dim SeparatorHeight As Integer = 1

        'label height
        Dim FormHeight As Integer = FontHeight + 4

        If ISPReturnData.ErrorMessage <> "" Then
            'error
            FormHeight += FontHeight * 4
        Else
            'ISPGraph
            If NewConfigurationData.ShowISPGraph = True Then
                FormHeight += SeparatorHeight
                FormHeight += ISPReturnData.GraphItemList.Count * (FontHeight + 6)
                FormHeight += 5
            End If

            'ISP stats
            If NewConfigurationData.ShowISPStats = True Then
                FormHeight += SeparatorHeight
                FormHeight += ISPReturnData.TextItemList.Count * FontHeight
                FormHeight += 1
            End If

            'NIC Stats
            If NewConfigurationData.RetrieveNICData = True Then
                If NewConfigurationData.ShowNICStats = True Then
                    FormHeight += SeparatorHeight + 1
                    FormHeight += FontHeight * 2

                    'offpeak exist?
                    If NewConfigurationData.OffpeakAvailable = True Then
                        If NewConfigurationData.WAIXAvailable = True Then
                            'waix
                            FormHeight += FontHeight
                        Else
                            'yes
                            FormHeight += FontHeight * 2
                        End If
                    End If
                End If
            End If
        End If

        Return New Point(FormWidth, FormHeight)
    End Function

    Sub DrawISPForm(ByVal UABitmap As Bitmap, ByVal ISPReturnData As ISPReturnData, ByVal NewConfigurationData As ConfigurationData, Optional ByVal ShowNicGraph As Boolean = False)

        Dim NewString As String

        Dim XOffset As Integer = 0
        Dim YOffset As Integer = 1
        Dim ISPLabelPanelHeight As Integer = FontHeight + 3
        Dim ISPGraphPanelHeight As Integer = 0
        Dim ISPStatsPanelHeight As Integer = 0
        Dim NICStatsPanelHeight As Integer = 0

        Dim g As Graphics = Graphics.FromImage(UABitmap)

        'apply opacity
        Dim NewForeColor As Color = Color.FromArgb(CInt(NewConfigurationData.ForeColour))
        Dim NewBackColor As Color = Color.FromArgb(CInt(NewConfigurationData.BackColour))

        '###########################################################

        'set quality
        If NewConfigurationData.ShowBackground = True Then
            g.TextRenderingHint = Text.TextRenderingHint.ClearTypeGridFit
        Else
            g.TextRenderingHint = Text.TextRenderingHint.SystemDefault
        End If

        g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

        'set brush
        Dim myBrush As New SolidBrush(NewForeColor)

        '###########################################################

        'draw label
        If NewConfigurationData.ShowBackground = True Then DrawRoundedRectangle(g, 0, 0, UABitmap.Width - 1, ISPLabelPanelHeight, NewBackColor, True, False)

        If ISPReturnData.Status = 3 Then
            NewString = NewConfigurationData.ISPName & " @ " & Format(Now, "h:mm tt - d MMM yy")
        Else
            NewString = NewConfigurationData.ISPName & " @ " & Format(ISPReturnData.LastUpdated, "h:mm tt - d MMM yy")
        End If

        XOffset = CInt((UABitmap.Width / 2) - (g.MeasureString(NewString, RegularFont, 1000, StringFormat.GenericTypographic).Width / 2))

        DrawOutlinedText(NewConfigurationData.ShowBackground, NewForeColor, g, NewString, RegularFont, XOffset, YOffset)

        'draw separator
        g.DrawLine(Pens.White, 0, ISPLabelPanelHeight + 1, UABitmap.Width, ISPLabelPanelHeight + 1)
        g.DrawLine(New Pen(Color.FromArgb(150, NewBackColor.R, NewBackColor.G, NewBackColor.B)), 0, ISPLabelPanelHeight + 1, UABitmap.Width, ISPLabelPanelHeight + 1)

        '#############################################################

        'check for error
        If ISPReturnData.Status = 3 Then
            Try
                'draw error background
                g.ResetTransform()
                DrawRoundedRectangle(g, 0, ISPLabelPanelHeight + 2, UABitmap.Width - 1, UABitmap.Height - (ISPLabelPanelHeight + 3), NewBackColor, False, True)

                'draw error text
                g.ResetTransform()
                Dim NewStringFormat As New StringFormat
                NewStringFormat.FormatFlags = StringFormatFlags.FitBlackBox
                NewStringFormat.Alignment = StringAlignment.Center
                Dim layoutSize As New SizeF(UABitmap.Width, 50)
                Dim stringSize As New SizeF(g.MeasureString(ISPReturnData.ErrorMessage, RegularFont, layoutSize, NewStringFormat))
                'define bounding rectangle in which to draw
                Dim StartY As Single = CSng((ISPLabelPanelHeight + 3) + ((UABitmap.Height - (ISPLabelPanelHeight + 3)) / 2) - (stringSize.Height / 2))
                Dim DrawRect As New RectangleF(0, StartY, UABitmap.Width, stringSize.Height)
                g.DrawString(ISPReturnData.ErrorMessage, RegularFont, myBrush, DrawRect, NewStringFormat)
                NewStringFormat.Dispose()
            Catch ex1 As Exception
            End Try
        Else

            YOffset = ISPLabelPanelHeight + 2

            '################################################

            'DrawISPGraph
            If NewConfigurationData.ShowISPGraph = True Then

                'calculate height of graph panel
                ISPGraphPanelHeight = (ISPReturnData.GraphItemList.Count * (FontHeight + 6)) + 4

                'draw background
                If NewConfigurationData.ShowBackground = True Then
                    If (ISPLabelPanelHeight + 3 + ISPGraphPanelHeight) >= UABitmap.Height Then
                        If ShowNicGraph = False Then
                            DrawRoundedRectangle(g, 0, ISPLabelPanelHeight + 2, UABitmap.Width - 1, ISPGraphPanelHeight, NewBackColor, False, True)
                        Else
                            DrawRoundedRectangle(g, 0, ISPLabelPanelHeight + 2, UABitmap.Width - 1, ISPGraphPanelHeight, NewBackColor, False, False)
                        End If
                    Else
                        DrawRoundedRectangle(g, 0, ISPLabelPanelHeight + 2, UABitmap.Width - 1, ISPGraphPanelHeight, NewBackColor, False, False)
                    End If
                End If

                'draw graph
                DrawISPGraph(UABitmap, YOffset, ISPReturnData, NewConfigurationData.IconISPUsageColourValue, NewConfigurationData.ShowBackground, NewForeColor)

                YOffset += ISPGraphPanelHeight + 2

                'draw separator
                g.DrawLine(Pens.White, 0, YOffset - 1, UABitmap.Width, YOffset - 1)
                g.DrawLine(New Pen(Color.FromArgb(150, NewBackColor.R, NewBackColor.G, NewBackColor.B)), 0, YOffset - 1, UABitmap.Width, YOffset - 1)
            End If

            '################################################

            'draw ISP stats
            If NewConfigurationData.ShowISPStats = True Then
                'calculate height of stats panel
                ISPStatsPanelHeight = (ISPReturnData.TextItemList.Count * FontHeight)

                'draw background
                If NewConfigurationData.ShowBackground = True Then
                    If (YOffset + ISPStatsPanelHeight + 1) >= UABitmap.Height Then
                        If ShowNicGraph = False Then
                            DrawRoundedRectangle(g, 0, YOffset, UABitmap.Width - 1, ISPStatsPanelHeight, NewBackColor, False, True)
                        Else
                            DrawRoundedRectangle(g, 0, YOffset, UABitmap.Width - 1, ISPStatsPanelHeight, NewBackColor, False, False)
                        End If
                    Else
                        DrawRoundedRectangle(g, 0, YOffset, UABitmap.Width - 1, ISPStatsPanelHeight, NewBackColor, False, False)
                    End If
                End If

                'draw ISP stats
                DrawISPStats(g, YOffset, NewConfigurationData, ISPReturnData)

                YOffset += ISPStatsPanelHeight + 2

                'draw separator
                g.DrawLine(Pens.White, 0, YOffset - 1, UABitmap.Width, YOffset - 1)
                g.DrawLine(New Pen(Color.FromArgb(150, NewBackColor.R, NewBackColor.G, NewBackColor.B)), 0, YOffset - 1, UABitmap.Width, YOffset - 1)
            End If

            '##################################################

            If NewConfigurationData.RetrieveNICData = True Then
                'get nic data
                Dim SumDownloadChange As Double
                Dim SumUploadChange As Double
                Dim SumOffpeakDownloadChange As Double
                Dim SumOffpeakUploadChange As Double

                'get nic data
                RetrieveNICData(ISPReturnData, SumDownloadChange, SumUploadChange, SumOffpeakDownloadChange, SumOffpeakUploadChange)

                'NIC Stats
                If NewConfigurationData.ShowNICStats = True Then
                    'draw NIC stats background
                    NICStatsPanelHeight = FontHeight * 2
                    'set ISP data
                    If Val(NewConfigurationData.OffpeakStartHour) <> 0 Or Val(NewConfigurationData.OffpeakEndHour) <> 0 Then
                        If NewConfigurationData.OffpeakStartHour = NewConfigurationData.OffpeakEndHour Then
                            'waix
                            NICStatsPanelHeight += FontHeight
                        Else
                            NICStatsPanelHeight += FontHeight * 2
                        End If
                    End If
                    If NewConfigurationData.ShowBackground = True Then
                        If (YOffset + NICStatsPanelHeight + 1) >= UABitmap.Height Then
                            If ShowNicGraph = False Then
                                DrawRoundedRectangle(g, 0, YOffset, UABitmap.Width - 1, NICStatsPanelHeight, NewBackColor, False, True)
                            Else
                                DrawRoundedRectangle(g, 0, YOffset, UABitmap.Width - 1, NICStatsPanelHeight, NewBackColor, False, False)
                            End If
                        Else
                            DrawRoundedRectangle(g, 0, YOffset, UABitmap.Width - 1, NICStatsPanelHeight, NewBackColor, False, False)
                        End If
                    End If

                    'draw nic stats
                    DrawNICStats(g, YOffset - 3, NewConfigurationData, ISPReturnData, SumDownloadChange, SumUploadChange, SumOffpeakDownloadChange, SumOffpeakUploadChange)
                End If
            End If
        End If

        'show warning?
        If ISPReturnData.ShowWarning = True Then g.DrawImageUnscaled(imgWarning, 1, 0)

        '########################################################

        'clean up
        myBrush.Dispose()

        g.Dispose()

        '########################################################

        'export if required
        Try
            If NewConfigurationData.ExportImage = True And My.Computer.FileSystem.DirectoryExists(NewConfigurationData.ExportImagePath) = True Then
                'save bitmap
                UABitmap.Save(NewConfigurationData.ExportImagePath & Path.DirectorySeparatorChar & "uaimage.png", System.Drawing.Imaging.ImageFormat.Png)

                If NewConfigurationData.ExportHTML = True Then

                    'read template.htm
                    Dim sr As New StreamReader(Application.StartupPath & Path.DirectorySeparatorChar & "template.htm")
                    Dim strHTML As String = sr.ReadToEnd()
                    sr.Close()

                    'insert path
                    If NewConfigurationData.ExportLocalHTMLPath = True Then
                        strHTML = Replace(strHTML, "<imagepath>", "file:///" & Replace(NewConfigurationData.ExportImagePath, ":", "|") & Path.DirectorySeparatorChar)
                    Else
                        strHTML = Replace(strHTML, "<imagepath>", "")
                    End If

                    'create HTML file
                    Dim sw As New StreamWriter(NewConfigurationData.ExportImagePath & Path.DirectorySeparatorChar & "ua.htm")
                    sw.Write(strHTML)
                    sw.Close()
                End If
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

    End Sub

    Function LoadConfiguration(ByRef NewConfigurationData As ConfigurationData) As Boolean
        LoadConfiguration = True
        AppDataPath = GetAppDataPath()

        Dim NewWallpaperFormData As WallpaperFormData
        NewConfigurationData.IconISPUsageColourValue.Items.Clear()

        Try
            If Dir(AppDataPath & "usageagent.cfg", FileAttribute.Normal) <> "" Then

                Dim strData() As String
                Dim strLine As String
                Dim strType As String = ""

                Using sr As New StreamReader(AppDataPath & "usageagent.cfg")
                    Do
                        strLine = sr.ReadLine
                        If strLine Is Nothing Then Exit Do

                        strData = strLine.Split("=".ToCharArray, 2)
                        If strData(0).StartsWith("[") And strData(0).EndsWith("]") Then
                            'set type
                            strType = strData(0)

                            'create wallpaper form class
                            If strType = "[ISPForm]" Then
                                NewWallpaperFormData = New WallpaperFormData(0)
                            ElseIf strType = "[WebForm]" Then
                                NewWallpaperFormData = New WallpaperFormData(1)
                            End If
                        Else
                            'set sub type
                            If strType = "[General]" Then

                                '################## Application update

                                If strData(0) = "CheckVersionOnStartup" Then
                                    NewConfigurationData.CheckVersionOnStartup = CBool(strData(1))
                                ElseIf strData(0) = "SendStats" Then
                                    NewConfigurationData.SendStats = CBool(strData(1))

                                    '################## ISP

                                ElseIf strData(0) = "ISPName" Then
                                    NewConfigurationData.ISPName = strData(1)
                                ElseIf strData(0) = "Username" Then
                                    NewConfigurationData.Username = strData(1)
                                ElseIf strData(0) = "ISPConnectionType" Then
                                    NewConfigurationData.ISPConnectionType = strData(1)
                                ElseIf strData(0) = "ISPServiceNo" Then
                                    NewConfigurationData.ISPServiceNo = strData(1)

                                    '################### ISP Plan

                                ElseIf strData(0) = "PeakUnlimited" Then
                                    NewConfigurationData.PeakUnlimited = CBool(strData(1))
                                ElseIf strData(0) = "PeakUsageLimit" Then
                                    NewConfigurationData.PeakUsageLimit = strData(1)
                                ElseIf strData(0) = "PeakReached" Then
                                    NewConfigurationData.PeakReached = strData(1)
                                ElseIf strData(0) = "OffpeakAvailable" Then
                                    NewConfigurationData.OffpeakAvailable = CBool(strData(1))
                                ElseIf strData(0) = "OffpeakStartHour" Then
                                    NewConfigurationData.OffpeakStartHour = strData(1)
                                ElseIf strData(0) = "OffpeakEndHour" Then
                                    NewConfigurationData.OffpeakEndHour = strData(1)
                                ElseIf strData(0) = "OffpeakTimeZone" Then
                                    NewConfigurationData.OffpeakTimeZone = strData(1)
                                ElseIf strData(0) = "OffpeakUnlimited" Then
                                    NewConfigurationData.OffpeakUnlimited = CBool(strData(1))
                                ElseIf strData(0) = "OffpeakUsageLimit" Then
                                    NewConfigurationData.OffpeakUsageLimit = strData(1)
                                ElseIf strData(0) = "OffpeakWeekendsUnlimited" Then
                                    NewConfigurationData.OffpeakWeekendsUnlimited = CBool(strData(1))
                                ElseIf strData(0) = "OffpeakReached" Then
                                    NewConfigurationData.OffpeakReached = strData(1)
                                ElseIf strData(0) = "OffpeakAvailableAfterPeakReached" Then
                                    NewConfigurationData.OffpeakAvailableAfterPeakReached = CBool(strData(1))
                                ElseIf strData(0) = "UploadCounted" Then
                                    NewConfigurationData.UploadCounted = CBool(strData(1))
                                ElseIf strData(0) = "UploadAvailable" Then
                                    NewConfigurationData.UploadAvailable = CBool(strData(1))
                                ElseIf strData(0) = "WAIXAvailable" Then
                                    NewConfigurationData.WAIXAvailable = CBool(strData(1))
                                ElseIf strData(0) = "ExcessApplicable" Then
                                    NewConfigurationData.ExcessApplicable = CBool(strData(1))
                                ElseIf strData(0) = "ExcessRate" Then
                                    NewConfigurationData.ExcessRate = strData(1)
                                ElseIf strData(0) = "ExcessMaxCharge" Then
                                    NewConfigurationData.ExcessMaxCharge = strData(1)
                                ElseIf strData(0) = "RolloverDay" Then
                                    NewConfigurationData.RolloverDay = strData(1)

                                    '################### Network Card

                                ElseIf strData(0) = "RetrieveNICData" Then
                                    NewConfigurationData.RetrieveNICData = CBool(strData(1))
                                ElseIf strData(0) = "NICName" Then
                                    NewConfigurationData.NICName = strData(1)

                                    '################### Update Interval

                                ElseIf strData(0) = "UpdateInterval" Then
                                    NewConfigurationData.UpdateInterval = CInt(strData(1))

                                    '################### Proxy

                                ElseIf strData(0) = "ProxyConnect" Then
                                    NewConfigurationData.ProxyConnect = CBool(strData(1))
                                ElseIf strData(0) = "ProxyName" Then
                                    NewConfigurationData.ProxyName = strData(1)
                                ElseIf strData(0) = "ProxyPort" Then
                                    NewConfigurationData.ProxyPort = strData(1)
                                ElseIf strData(0) = "ProxyLogin" Then
                                    NewConfigurationData.ProxyLogin = strData(1)

                                    '################### Logging

                                ElseIf strData(0) = "LogEnabled" Then
                                    NewConfigurationData.LogEnabled = CBool(strData(1))

                                    '################### Data Export

                                ElseIf strData(0) = "ExportTextLog" Then
                                    NewConfigurationData.ExportTextLog = CBool(strData(1))
                                ElseIf strData(0) = "ExportDescriptors" Then
                                    NewConfigurationData.ExportDescriptors = CBool(strData(1))
                                ElseIf strData(0) = "ExportNotations" Then
                                    NewConfigurationData.ExportNotations = CBool(strData(1))
                                ElseIf strData(0) = "ExportDownload" Then
                                    NewConfigurationData.ExportDownload = CBool(strData(1))
                                ElseIf strData(0) = "ExportRemaining" Then
                                    NewConfigurationData.ExportRemaining = CBool(strData(1))
                                ElseIf strData(0) = "ExportAverage" Then
                                    NewConfigurationData.ExportAverage = CBool(strData(1))
                                ElseIf strData(0) = "ExportAverageRemaining" Then
                                    NewConfigurationData.ExportAverageRemaining = CBool(strData(1))
                                ElseIf strData(0) = "ExportPlanLimit" Then
                                    NewConfigurationData.ExportPlanLimit = CBool(strData(1))
                                ElseIf strData(0) = "ExportShaped" Then
                                    NewConfigurationData.ExportShaped = CBool(strData(1))
                                ElseIf strData(0) = "ExportTime" Then
                                    NewConfigurationData.ExportTime = CBool(strData(1))
                                ElseIf strData(0) = "ExportUpload" Then
                                    NewConfigurationData.ExportUpload = CBool(strData(1))
                                ElseIf strData(0) = "ExportPath" Then
                                    NewConfigurationData.ExportPath = strData(1)

                                    '################### Image Export

                                ElseIf strData(0) = "ExportImage" Then
                                    NewConfigurationData.ExportImage = CBool(strData(1))
                                ElseIf strData(0) = "ExportHTML" Then
                                    NewConfigurationData.ExportHTML = CBool(strData(1))
                                ElseIf strData(0) = "ExportLocalHTMLPath" Then
                                    NewConfigurationData.ExportLocalHTMLPath = CBool(strData(1))
                                ElseIf strData(0) = "ExportImagePath" Then
                                    NewConfigurationData.ExportImagePath = strData(1)

                                    '################### Alerts

                                ElseIf strData(0) = "AlertEnable" Then
                                    NewConfigurationData.AlertEnable = CBool(strData(1))
                                ElseIf strData(0) = "AlertDialog" Then
                                    NewConfigurationData.AlertDialog = CBool(strData(1))
                                ElseIf strData(0) = "AlertEmail" Then
                                    NewConfigurationData.AlertEmail = CBool(strData(1))
                                ElseIf strData(0) = "AlertValue" Then
                                    NewConfigurationData.AlertValue.Items.Add(strData(1))
                                ElseIf strData(0) = "AlertMailTo" Then
                                    NewConfigurationData.AlertMailTo = strData(1)
                                ElseIf strData(0) = "AlertMailServer" Then
                                    NewConfigurationData.AlertMailServer = strData(1)

                                    '################### Display

                                ElseIf strData(0) = "Font" Then
                                    NewConfigurationData.Font = strData(1)
                                ElseIf strData(0) = "FontSize" Then
                                    NewConfigurationData.FontSize = CInt(strData(1))
                                    RegularFont = New Font(NewConfigurationData.Font, CSng(NewConfigurationData.FontSize * (96 / GetDPI())), FontStyle.Regular)
                                    BoldFont = New Font(NewConfigurationData.Font, CSng(NewConfigurationData.FontSize * (96 / GetDPI())), FontStyle.Bold)

                                    Dim TempBitmap As New Bitmap(1, 1)
                                    Dim g As Graphics = Graphics.FromImage(TempBitmap)
                                    StatsPosX = CInt(g.MeasureString("Offpeak Avg. Left :", RegularFont, 1000, StringFormat.GenericTypographic).Width) + 5
                                    TempBitmap.Dispose()
                                ElseIf strData(0) = "Opacity" Then
                                    NewConfigurationData.Opacity = strData(1)
                                ElseIf strData(0) = "ShowISPGraph" Then
                                    NewConfigurationData.ShowISPGraph = CBool(strData(1))
                                ElseIf strData(0) = "ShowISPStats" Then
                                    NewConfigurationData.ShowISPStats = CBool(strData(1))
                                ElseIf strData(0) = "ShowNICStats" Then
                                    NewConfigurationData.ShowNICStats = CBool(strData(1))
                                ElseIf strData(0) = "ISPUsageColourValue" Then
                                    Dim strUsageColourValue() As String = strData(1).Split(",".ToCharArray, 2)
                                    NewConfigurationData.IconISPUsageColourValue.Items.Add(New UsageColourValue(CInt(strUsageColourValue(0)), strUsageColourValue(1)))
                                ElseIf strData(0) = "ShowBackground" Then
                                    NewConfigurationData.ShowBackground = CBool(strData(1))
                                ElseIf strData(0) = "BackColour" Then
                                    NewConfigurationData.BackColour = strData(1)
                                ElseIf strData(0) = "ForeColour" Then
                                    NewConfigurationData.ForeColour = strData(1)

                                    '################### UA Icon

                                ElseIf strData(0) = "IconWindowsStartup" Then
                                    NewConfigurationData.IconWindowsStartup = CBool(strData(1))
                                ElseIf strData(0) = "IconStatsShowStartup" Then
                                    NewConfigurationData.IconStatsShowStartup = CBool(strData(1))
                                ElseIf strData(0) = "IconUpdateDelay" Then
                                    NewConfigurationData.IconUpdateDelay = CInt(strData(1))
                                ElseIf strData(0) = "IconShowNICGraph" Then
                                    NewConfigurationData.IconShowNICGraph = CBool(strData(1))
                                ElseIf strData(0) = "IconStatsTopmost" Then
                                    NewConfigurationData.IconStatsTopmost = CBool(strData(1))
                                ElseIf strData(0) = "IconStartX" Then
                                    NewConfigurationData.IconStartX = CInt(strData(1))
                                ElseIf strData(0) = "IconStartY" Then
                                    NewConfigurationData.IconStartY = CInt(strData(1))
                                ElseIf strData(0) = "IconNICCapacityDown" Then
                                    NewConfigurationData.IconNICCapacityDown = CInt(strData(1))
                                ElseIf strData(0) = "IconNICCapacityUp" Then
                                    NewConfigurationData.IconNICCapacityUp = CInt(strData(1))
                                ElseIf strData(0) = "IconTrayISPUsage" Then
                                    NewConfigurationData.IconTrayISPUsage = CBool(strData(1))
                                ElseIf strData(0) = "IconTrayISPColour" Then
                                    NewConfigurationData.IconTrayISPColour = CBool(strData(1))
                                ElseIf strData(0) = "IconTrayNICGraph" Then
                                    NewConfigurationData.IconTrayNICGraph = CBool(strData(1))

                                    '################### UA Wallpaper

                                ElseIf strData(0) = "WallpaperEnable" Then
                                    NewConfigurationData.WallpaperEnable = CBool(strData(1))
                                ElseIf strData(0) = "WallpaperWindowsStartup" Then
                                    NewConfigurationData.WallpaperWindowsStartup = CBool(strData(1))
                                ElseIf strData(0) = "WallpaperUnixCommand" Then
                                    NewConfigurationData.WallpaperUnixCommand = strData(1)
                                ElseIf strData(0) = "WallpaperUnixCommandArgs" Then
                                    NewConfigurationData.WallpaperUnixCommandArgs = strData(1)

                                    '################### Misc

                                ElseIf strData(0) = "ISPValidated" Then
                                    NewConfigurationData.ISPValidated = CBool(strData(1))
                                ElseIf strData(0) = "LastNotify" Then
                                    NewConfigurationData.LastNotify = strData(1)
                                ElseIf strData(0) = "Alert1Count" Then
                                    NewConfigurationData.Alert1Count = CInt(strData(1))
                                ElseIf strData(0) = "Alert2Count" Then
                                    NewConfigurationData.Alert2Count = CInt(strData(1))
                                ElseIf strData(0) = "Alert3Count" Then
                                    NewConfigurationData.Alert3Count = CInt(strData(1))
                                ElseIf strData(0) = "Alert4Count" Then
                                    NewConfigurationData.Alert4Count = CInt(strData(1))
                                ElseIf strData(0) = "Alert5Count" Then
                                    NewConfigurationData.Alert5Count = CInt(strData(1))
                                ElseIf strData(0) = "Version" Then
                                    NewConfigurationData.Version = strData(1)
                                ElseIf strData(0) = "VistaGadgetEnable" Then
                                    NewConfigurationData.VistaGadgetEnable = CBool(strData(1))
                                End If

                            ElseIf strType = "[ISPForm]" Then
                                If strData(0) = "X" Then
                                    NewWallpaperFormData.X = strData(1)
                                ElseIf strData(0) = "Y" Then
                                    NewWallpaperFormData.Y = strData(1)
                                    'add to list
                                    NewConfigurationData.WallpaperFormList.Add(NewWallpaperFormData)
                                End If

                            ElseIf strType = "[WebForm]" Then
                                If strData(0) = "ShowLabel" Then
                                    NewWallpaperFormData.ShowLabel = CBool(strData(1))
                                ElseIf strData(0) = "Label" Then
                                    NewWallpaperFormData.Label = strData(1)
                                ElseIf strData(0) = "URL" Then
                                    NewWallpaperFormData.URL = strData(1)
                                ElseIf strData(0) = "StretchImage" Then
                                    NewWallpaperFormData.StretchImage = CBool(strData(1))
                                ElseIf strData(0) = "MaintainAspectRatio" Then
                                    NewWallpaperFormData.MaintainAspectRatio = CBool(strData(1))
                                ElseIf strData(0) = "Zoom" Then
                                    NewWallpaperFormData.Zoom = CBool(strData(1))
                                ElseIf strData(0) = "ZoomX" Then
                                    NewWallpaperFormData.ZoomX = strData(1)
                                ElseIf strData(0) = "ZoomY" Then
                                    NewWallpaperFormData.ZoomY = strData(1)
                                ElseIf strData(0) = "ZoomWidth" Then
                                    NewWallpaperFormData.ZoomWidth = strData(1)
                                ElseIf strData(0) = "ZoomHeight" Then
                                    NewWallpaperFormData.ZoomHeight = strData(1)
                                ElseIf strData(0) = "Width" Then
                                    NewWallpaperFormData.Width = strData(1)
                                ElseIf strData(0) = "Height" Then
                                    NewWallpaperFormData.Height = strData(1)
                                ElseIf strData(0) = "X" Then
                                    NewWallpaperFormData.X = strData(1)
                                ElseIf strData(0) = "Y" Then
                                    NewWallpaperFormData.Y = strData(1)
                                ElseIf strData(0) = "ShowBackground" Then
                                    NewWallpaperFormData.ShowBackground = CBool(strData(1))
                                ElseIf strData(0) = "BackColour" Then
                                    NewWallpaperFormData.BackColour = strData(1)
                                ElseIf strData(0) = "ForeColour" Then
                                    NewWallpaperFormData.ForeColour = strData(1)
                                ElseIf strData(0) = "Opacity" Then
                                    NewWallpaperFormData.Opacity = strData(1)
                                    'add to list
                                    NewConfigurationData.WallpaperFormList.Add(NewWallpaperFormData)
                                End If
                            End If
                        End If
                    Loop
                    sr.Close()
                End Using

            Else
                LoadConfiguration = False

                'add isp form
                NewWallpaperFormData = New WallpaperFormData(0)

                NewWallpaperFormData.X = "0"
                NewWallpaperFormData.Y = "0"
                'add to list
                NewConfigurationData.WallpaperFormList.Add(NewWallpaperFormData)
            End If

            'if there are no colour entries, use default
            If NewConfigurationData.IconISPUsageColourValue.Items.Count = 0 Then SetDefaultUsageColourValue(NewConfigurationData.IconISPUsageColourValue)

            'if there are no alert entries, use default
            If NewConfigurationData.AlertValue.Items.Count = 0 Then SetDefaultAlertValue(NewConfigurationData.AlertValue)

            'get proxy password
            NewConfigurationData.ProxyPassword = LoadPassword("proxy.dat")

            'set global proxy server if required
            If NewConfigurationData.ProxyConnect = True Then SetProxyServer(NewConfigurationData.ProxyName, NewConfigurationData.ProxyPort, NewConfigurationData.ProxyLogin, NewConfigurationData.ProxyPassword)

            If Val(Replace(NewConfigurationData.Version, ".", "")) < 9000 Then
                If My.Computer.FileSystem.FileExists(AppDataPath & "account.dat") = True Then My.Computer.FileSystem.DeleteFile(AppDataPath & "account.dat")
                If My.Computer.FileSystem.FileExists(AppDataPath & "proxy.dat") = True Then My.Computer.FileSystem.DeleteFile(AppDataPath & "proxy.dat")
            End If

            'get password
            NewConfigurationData.Password = LoadPassword("account.dat")
            If NewConfigurationData.Password = "" Then LoadConfiguration = False

        Catch ex As Exception
            MessageBox.Show(ex.ToString & vbCrLf & "Error reading config file.", "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            LoadConfiguration = False
        End Try

    End Function

    Function SaveConfiguration(ByRef NewConfigurationData As ConfigurationData, Optional ByVal QuickSave As Boolean = True, Optional ByVal ImageWidth As Integer = 0, Optional ByVal ImageHeight As Integer = 0) As Boolean
        SaveConfiguration = False

        Try
            Using sw As New StreamWriter(AppDataPath & "usageagent.cfg")
                sw.WriteLine("[General]")

                'Application Update
                sw.WriteLine("CheckVersionOnStartup=" & NewConfigurationData.CheckVersionOnStartup)
                sw.WriteLine("SendStats=" & NewConfigurationData.SendStats)

                'ISP
                sw.WriteLine("ISPName=" & NewConfigurationData.ISPName)
                sw.WriteLine("Username=" & NewConfigurationData.Username)
                sw.WriteLine("ISPConnectionType=" & NewConfigurationData.ISPConnectionType)
                sw.WriteLine("ISPServiceNo=" & NewConfigurationData.ISPServiceNo)

                'ISP Plan
                sw.WriteLine("PeakUnlimited=" & NewConfigurationData.PeakUnlimited)
                sw.WriteLine("PeakUsageLimit=" & NewConfigurationData.PeakUsageLimit)
                sw.WriteLine("PeakReached=" & NewConfigurationData.PeakReached)
                sw.WriteLine("OffpeakAvailable=" & NewConfigurationData.OffpeakAvailable)
                sw.WriteLine("OffpeakStartHour=" & NewConfigurationData.OffpeakStartHour)
                sw.WriteLine("OffpeakEndHour=" & NewConfigurationData.OffpeakEndHour)
                sw.WriteLine("OffpeakTimeZone=" & NewConfigurationData.OffpeakTimeZone)
                sw.WriteLine("OffpeakUnlimited=" & NewConfigurationData.OffpeakUnlimited)
                sw.WriteLine("OffpeakUsageLimit=" & NewConfigurationData.OffpeakUsageLimit)
                sw.WriteLine("OffpeakWeekendsUnlimited=" & NewConfigurationData.OffpeakWeekendsUnlimited)
                sw.WriteLine("OffpeakReached=" & NewConfigurationData.OffpeakReached)
                sw.WriteLine("OffpeakAvailableAfterPeakReached=" & NewConfigurationData.OffpeakAvailableAfterPeakReached)
                sw.WriteLine("UploadCounted=" & NewConfigurationData.UploadCounted)
                sw.WriteLine("UploadAvailable=" & NewConfigurationData.UploadAvailable)
                sw.WriteLine("WAIXAvailable=" & NewConfigurationData.WAIXAvailable)
                sw.WriteLine("ExcessApplicable=" & NewConfigurationData.ExcessApplicable)
                sw.WriteLine("ExcessRate=" & NewConfigurationData.ExcessRate)
                sw.WriteLine("ExcessMaxCharge=" & NewConfigurationData.ExcessMaxCharge)
                sw.WriteLine("RolloverDay=" & NewConfigurationData.RolloverDay)

                'Network Card
                sw.WriteLine("RetrieveNICData=" & NewConfigurationData.RetrieveNICData)
                sw.WriteLine("NICName=" & NewConfigurationData.NICName)

                'Update Interval
                sw.WriteLine("UpdateInterval=" & NewConfigurationData.UpdateInterval)

                'Proxy
                sw.WriteLine("ProxyConnect=" & NewConfigurationData.ProxyConnect)
                sw.WriteLine("ProxyName=" & NewConfigurationData.ProxyName)
                sw.WriteLine("ProxyPort=" & NewConfigurationData.ProxyPort)
                sw.WriteLine("ProxyLogin=" & NewConfigurationData.ProxyLogin)

                'Logging
                sw.WriteLine("LogEnabled=" & NewConfigurationData.LogEnabled)

                'Data Export
                sw.WriteLine("ExportTextLog=" & NewConfigurationData.ExportTextLog)
                sw.WriteLine("ExportDescriptors=" & NewConfigurationData.ExportDescriptors)
                sw.WriteLine("ExportNotations=" & NewConfigurationData.ExportNotations)
                sw.WriteLine("ExportDownload=" & NewConfigurationData.ExportDownload)
                sw.WriteLine("ExportRemaining=" & NewConfigurationData.ExportRemaining)
                sw.WriteLine("ExportAverage=" & NewConfigurationData.ExportAverage)
                sw.WriteLine("ExportAverageRemaining=" & NewConfigurationData.ExportAverageRemaining)
                sw.WriteLine("ExportPlanLimit=" & NewConfigurationData.ExportPlanLimit)
                sw.WriteLine("ExportShaped=" & NewConfigurationData.ExportShaped)
                sw.WriteLine("ExportTime=" & NewConfigurationData.ExportTime)
                sw.WriteLine("ExportUpload=" & NewConfigurationData.ExportUpload)
                sw.WriteLine("ExportPath=" & NewConfigurationData.ExportPath)

                'Image Export
                sw.WriteLine("ExportImage=" & NewConfigurationData.ExportImage)
                sw.WriteLine("ExportHTML=" & NewConfigurationData.ExportHTML)
                sw.WriteLine("ExportLocalHTMLPath=" & NewConfigurationData.ExportLocalHTMLPath)
                sw.WriteLine("ExportImagePath=" & NewConfigurationData.ExportImagePath)

                'Alerts
                sw.WriteLine("AlertEnable=" & NewConfigurationData.AlertEnable)
                sw.WriteLine("AlertDialog=" & NewConfigurationData.AlertDialog)
                sw.WriteLine("AlertEmail=" & NewConfigurationData.AlertEmail)
                For Each AlertValue As String In NewConfigurationData.AlertValue.Items
                    sw.WriteLine("AlertValue=" & AlertValue)
                Next
                sw.WriteLine("AlertMailTo=" & NewConfigurationData.AlertMailTo)
                sw.WriteLine("AlertMailServer=" & NewConfigurationData.AlertMailServer)

                'Display
                sw.WriteLine("Font=" & NewConfigurationData.Font)
                sw.WriteLine("FontSize=" & NewConfigurationData.FontSize)
                sw.WriteLine("Opacity=" & NewConfigurationData.Opacity)
                sw.WriteLine("ShowISPGraph=" & NewConfigurationData.ShowISPGraph)
                sw.WriteLine("ShowISPStats=" & NewConfigurationData.ShowISPStats)
                sw.WriteLine("ShowNICStats=" & NewConfigurationData.ShowNICStats)
                For Each NewUsageColourValue As UsageColourValue In NewConfigurationData.IconISPUsageColourValue.Items
                    sw.WriteLine("ISPUsageColourValue=" & NewUsageColourValue.Percentage.ToString & "," & NewUsageColourValue.Value)
                Next
                sw.WriteLine("ShowBackground=" & NewConfigurationData.ShowBackground)
                sw.WriteLine("BackColour=" & NewConfigurationData.BackColour)
                sw.WriteLine("ForeColour=" & NewConfigurationData.ForeColour)

                'UA Icon
                sw.WriteLine("IconWindowsStartup=" & NewConfigurationData.IconWindowsStartup)
                sw.WriteLine("IconStatsShowStartup=" & NewConfigurationData.IconStatsShowStartup)
                sw.WriteLine("IconUpdateDelay=" & NewConfigurationData.IconUpdateDelay)
                sw.WriteLine("IconShowNICGraph=" & NewConfigurationData.IconShowNICGraph)
                sw.WriteLine("IconStatsTopmost=" & NewConfigurationData.IconStatsTopmost)
                sw.WriteLine("IconStartX=" & NewConfigurationData.IconStartX)
                sw.WriteLine("IconStartY=" & NewConfigurationData.IconStartY)
                sw.WriteLine("IconNICCapacityDown=" & NewConfigurationData.IconNICCapacityDown)
                sw.WriteLine("IconNICCapacityUp=" & NewConfigurationData.IconNICCapacityUp)
                sw.WriteLine("IconTrayISPUsage=" & NewConfigurationData.IconTrayISPUsage)
                sw.WriteLine("IconTrayISPColour=" & NewConfigurationData.IconTrayISPColour)
                sw.WriteLine("IconTrayNICGraph=" & NewConfigurationData.IconTrayNICGraph)

                'UA Wallpaper
                sw.WriteLine("WallpaperEnable=" & NewConfigurationData.WallpaperEnable)
                sw.WriteLine("WallpaperWindowsStartup=" & NewConfigurationData.WallpaperWindowsStartup)
                sw.WriteLine("WallpaperUnixCommand=" & NewConfigurationData.WallpaperUnixCommand)
                sw.WriteLine("WallpaperUnixCommandArgs=" & NewConfigurationData.WallpaperUnixCommandArgs)

                'Misc
                sw.WriteLine("ISPValidated=" & NewConfigurationData.ISPValidated)
                sw.WriteLine("LastNotify=" & NewConfigurationData.LastNotify)
                sw.WriteLine("Alert1Count=" & NewConfigurationData.Alert1Count)
                sw.WriteLine("Alert2Count=" & NewConfigurationData.Alert2Count)
                sw.WriteLine("Alert3Count=" & NewConfigurationData.Alert3Count)
                sw.WriteLine("Alert4Count=" & NewConfigurationData.Alert4Count)
                sw.WriteLine("Alert5Count=" & NewConfigurationData.Alert5Count)
                sw.WriteLine("Version=" & Application.ProductVersion)
                sw.WriteLine("VistaGadgetEnable=" & NewConfigurationData.VistaGadgetEnable)

                'UA Wallpaper Form List
                'go through each form and save
                For Each NewFormData As WallpaperFormData In NewConfigurationData.WallpaperFormList
                    If NewFormData.FormType = 0 Then
                        sw.WriteLine("[ISPForm]")
                    ElseIf NewFormData.FormType = 1 Then
                        sw.WriteLine("[WebForm]")
                        sw.WriteLine("ShowLabel=" & NewFormData.ShowLabel.ToString)
                        sw.WriteLine("Label=" & NewFormData.Label)
                        sw.WriteLine("URL=" & NewFormData.URL)
                        sw.WriteLine("StretchImage=" & NewFormData.StretchImage.ToString)
                        sw.WriteLine("MaintainAspectRatio=" & NewFormData.MaintainAspectRatio.ToString)
                        sw.WriteLine("Zoom=" & NewFormData.Zoom.ToString)
                        sw.WriteLine("ZoomX=" & NewFormData.ZoomX)
                        sw.WriteLine("ZoomY=" & NewFormData.ZoomY)
                        sw.WriteLine("ZoomWidth=" & NewFormData.ZoomWidth)
                        sw.WriteLine("ZoomHeight=" & NewFormData.ZoomHeight)
                        sw.WriteLine("ShowBackground=" & NewFormData.ShowBackground.ToString)
                        sw.WriteLine("BackColour=" & NewFormData.BackColour)
                        sw.WriteLine("ForeColour=" & NewFormData.ForeColour)
                        sw.WriteLine("Opacity=" & NewFormData.Opacity)
                        sw.WriteLine("Width=" & NewFormData.Width)
                        sw.WriteLine("Height=" & NewFormData.Height)
                    End If
                    sw.WriteLine("X=" & NewFormData.X)
                    sw.WriteLine("Y=" & NewFormData.Y)
                Next

                sw.Close()
            End Using

            'only full save if coming from the config app
            If QuickSave = False Then
                'write isp password to file
                SavePassword(NewConfigurationData.Password, "account.dat")

                'write proxy password to file
                If NewConfigurationData.ProxyConnect = True And NewConfigurationData.ProxyPassword <> "" Then
                    SavePassword(NewConfigurationData.ProxyPassword, "proxy.dat")
                Else
                    Try
                        'delete password file
                        If Dir(AppDataPath & "proxy.dat", FileAttribute.Normal) <> "" Then
                            Kill(AppDataPath & "proxy.dat")
                        End If
                    Catch ex As Exception
                    End Try
                End If

                'set global proxy server if required
                If NewConfigurationData.ProxyConnect = True Then SetProxyServer(NewConfigurationData.ProxyName, NewConfigurationData.ProxyPort, NewConfigurationData.ProxyLogin, NewConfigurationData.ProxyPassword)

                'set windows startup
                If UnixDetected() = False Then
                    Dim RegKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Run", True)
                    If NewConfigurationData.IconWindowsStartup = True Then
                        RegKey.SetValue("UATrayIcon", Application.StartupPath & Path.DirectorySeparatorChar & "UATrayIcon.exe")
                    Else
                        If Format(RegKey.GetValue("UATrayIcon")) <> "" Then RegKey.DeleteValue("UATrayIcon")
                    End If
                    If NewConfigurationData.WallpaperEnable = True And NewConfigurationData.WallpaperWindowsStartup = True Then
                        RegKey.SetValue("UAWallpaper", Application.StartupPath & Path.DirectorySeparatorChar & "UAWallpaper.exe")
                    Else
                        If Format(RegKey.GetValue("UAWallpaper")) <> "" Then RegKey.DeleteValue("UAWallpaper")
                    End If
                    RegKey.Close()

                    'set windows shutdown
                    'delete all existing shutdown entries
                    Dim RootPath1 As String = "SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts"
                    Dim RootPath2 As String = "SOFTWARE\Policies\Microsoft\Windows\System\Scripts"
                    RemoveShutdownScript(Application.StartupPath & Path.DirectorySeparatorChar & "UAShutdownUpdate.exe", RootPath1)
                    RemoveShutdownScript(Application.StartupPath & Path.DirectorySeparatorChar & "UAShutdownUpdate.exe", RootPath2)
                    'recreate entries
                    If NewConfigurationData.RetrieveNICData = True And NewConfigurationData.LogEnabled = True Then
                        AddShutdownScript(Application.StartupPath & Path.DirectorySeparatorChar & "UAShutdownUpdate.exe", RootPath1)
                        AddShutdownScript(Application.StartupPath & Path.DirectorySeparatorChar & "UAShutdownUpdate.exe", RootPath2)
                    End If
                End If

                If UnixDetected() = False Then
                    'set UAWallpaper scheduled tasks if required
                    Dim NewScheduledTasks As ScheduledTasks
                    Try
                        NewScheduledTasks = New ScheduledTasks
                        'go though all tasks and delete existing UAWallpaper tasks
                        For Each TaskName As String In NewScheduledTasks.GetTaskNames
                            If TaskName.StartsWith("UAWallpaper") = True Then
                                NewScheduledTasks.DeleteTask(TaskName)
                            End If
                        Next

                        If NewConfigurationData.WallpaperEnable = True And NewConfigurationData.WallpaperFormList.Count > 0 Then
                            Dim NewTrigger As DailyTrigger
                            Dim NewTime As DateTime
                            Dim StartHour As Short
                            Dim TaskCount As Integer = 1

                            'create main wallpaper task
                            Dim NewTask As Task = NewScheduledTasks.CreateTask("UAWallpaper " & TaskCount)
                            NewTask.Flags = TaskFlags.RunOnlyIfLoggedOn
                            NewTask.SetAccountInformation(Environment.MachineName & "\" & Environment.UserName, Nothing)
                            NewTask.ApplicationName = Application.StartupPath & Path.DirectorySeparatorChar & "uawallpaper.exe"
                            NewTask.WorkingDirectory = Application.StartupPath
                            NewTask.Comment = "Auto Generated by Usage Agent Wallpaper"
                            NewTime = Now.AddMinutes(5)
                            NewTrigger = New DailyTrigger(CShort(NewTime.Hour), CShort(NewTime.Minute))
                            NewTrigger.DurationMinutes = 1440
                            NewTrigger.IntervalMinutes = CInt(NewConfigurationData.UpdateInterval)
                            NewTask.Triggers.Add(NewTrigger)
                            NewTask.Save()
                            NewTask.Dispose()

                            If NewConfigurationData.OffpeakStartHour <> "0" Or NewConfigurationData.OffpeakEndHour <> "0" Then
                                'only add if not WAIX
                                If NewConfigurationData.OffpeakStartHour <> NewConfigurationData.OffpeakEndHour Then
                                    'create tasks just before offpeak start time
                                    TaskCount += 1
                                    NewTask = NewScheduledTasks.CreateTask("UAWallpaper " & TaskCount)
                                    NewTask.Flags = TaskFlags.RunOnlyIfLoggedOn
                                    NewTask.SetAccountInformation(Environment.MachineName & "\" & Environment.UserName, Nothing)
                                    NewTask.ApplicationName = Application.StartupPath & Path.DirectorySeparatorChar & "uawallpaper.exe"
                                    NewTask.WorkingDirectory = Application.StartupPath
                                    NewTask.Comment = "Auto Generated by Usage Agent Wallpaper"
                                    If NewConfigurationData.OffpeakStartHour = "0" Then
                                        StartHour = 23
                                    Else
                                        StartHour = CShort(Val(NewConfigurationData.OffpeakStartHour) - 1)
                                    End If
                                    NewTrigger = New DailyTrigger(StartHour, 59)
                                    NewTask.Triggers.Add(NewTrigger)
                                    NewTask.Save()
                                    NewTask.Dispose()

                                    'create tasks just before offpeak end time
                                    TaskCount += 1
                                    NewTask = NewScheduledTasks.CreateTask("UAWallpaper " & TaskCount)
                                    NewTask.Flags = TaskFlags.RunOnlyIfLoggedOn
                                    NewTask.SetAccountInformation(Environment.MachineName & "\" & Environment.UserName, Nothing)
                                    NewTask.ApplicationName = Application.StartupPath & Path.DirectorySeparatorChar & "uawallpaper.exe"
                                    NewTask.WorkingDirectory = Application.StartupPath
                                    NewTask.Comment = "Auto Generated by Usage Agent Wallpaper"
                                    If NewConfigurationData.OffpeakEndHour = "0" Then
                                        StartHour = 23
                                    Else
                                        StartHour = CShort(Val(NewConfigurationData.OffpeakEndHour) - 1)
                                    End If
                                    NewTrigger = New DailyTrigger(StartHour, 59)
                                    NewTask.Triggers.Add(NewTrigger)
                                    NewTask.Save()
                                    NewTask.Dispose()
                                End If
                            End If
                        End If
                    Catch ex As Exception
                    Finally
                        If NewScheduledTasks IsNot Nothing Then NewScheduledTasks.Dispose()
                    End Try

                    'set UAImage for Vista Gadget scheduled tasks if required
                    If VistaDetected() = True Then

                        Try
                            NewScheduledTasks = New ScheduledTasks
                            'go though all tasks and delete existing UAImage tasks
                            For Each TaskName As String In NewScheduledTasks.GetTaskNames
                                If TaskName.StartsWith("UAImage") = True Then
                                    NewScheduledTasks.DeleteTask(TaskName)
                                End If
                            Next

                            'delete gadget files
                            Dim GadgetPath As String = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & Path.DirectorySeparatorChar & "Microsoft" & Path.DirectorySeparatorChar & "Windows Sidebar" & Path.DirectorySeparatorChar & "Gadgets" & Path.DirectorySeparatorChar
                            Try
                                My.Computer.FileSystem.DeleteDirectory(GadgetPath & "UsageAgent.Gadget", FileIO.DeleteDirectoryOption.DeleteAllContents)
                            Catch ex As Exception
                            End Try

                            If NewConfigurationData.VistaGadgetEnable = True Then
                                'create gadget folder
                                Try
                                    My.Computer.FileSystem.CreateDirectory(GadgetPath & "UsageAgent.Gadget")
                                Catch ex As Exception
                                End Try

                                If My.Computer.FileSystem.DirectoryExists(GadgetPath & "UsageAgent.Gadget") = True Then
                                    Try
                                        'add gadget icon and xml
                                        Try
                                            My.Computer.FileSystem.CopyFile(Application.StartupPath & Path.DirectorySeparatorChar & "gadget.xml", GadgetPath & "UsageAgent.Gadget" & Path.DirectorySeparatorChar & "gadget.xml")
                                            My.Computer.FileSystem.CopyFile(Application.StartupPath & Path.DirectorySeparatorChar & "icon.png", GadgetPath & "UsageAgent.Gadget" & Path.DirectorySeparatorChar & "icon.png")
                                        Catch ex As Exception
                                        End Try

                                        'read UsageAgent.html
                                        Dim sr As New StreamReader(Application.StartupPath & Path.DirectorySeparatorChar & "UsageAgent.html")
                                        Dim strHTML As String = sr.ReadToEnd()
                                        sr.Close()

                                        'insert variables
                                        strHTML = Replace(strHTML, "<imagepath>", Replace(AppDataPath, Path.DirectorySeparatorChar, Path.DirectorySeparatorChar & Path.DirectorySeparatorChar))
                                        strHTML = Replace(strHTML, "<width>", ImageWidth.ToString)
                                        strHTML = Replace(strHTML, "<height>", ImageHeight.ToString)

                                        'create UsageAgent.html
                                        Dim sw As New StreamWriter(GadgetPath & "UsageAgent.Gadget" & Path.DirectorySeparatorChar & "UsageAgent.html")
                                        sw.Write(strHTML)
                                        sw.Close()

                                        'read flyout.html
                                        sr = New StreamReader(Application.StartupPath & Path.DirectorySeparatorChar & "flyout.html")
                                        strHTML = sr.ReadToEnd()
                                        sr.Close()

                                        'insert path
                                        strHTML = Replace(strHTML, "<apppath>", Replace(Application.StartupPath & Path.DirectorySeparatorChar, Path.DirectorySeparatorChar, Path.DirectorySeparatorChar & Path.DirectorySeparatorChar))
                                        strHTML = Replace(strHTML, "<ispurl>", GetISPHomePage(NewConfigurationData.ISPName))

                                        'create flyout.html
                                        sw = New StreamWriter(GadgetPath & "UsageAgent.Gadget" & Path.DirectorySeparatorChar & "flyout.html")
                                        sw.Write(strHTML)
                                        sw.Close()
                                    Catch ex As Exception
                                        MessageBox.Show(ex.ToString, "Usage Agent Configuration", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                                    End Try
                                End If

                                '#############################################################

                                Dim NewTrigger As DailyTrigger
                                Dim NewTime As DateTime
                                Dim StartHour As Short
                                Dim TaskCount As Integer = 1

                                'create main image task
                                Dim NewTask As Task = NewScheduledTasks.CreateTask("UAImage " & TaskCount)
                                NewTask.Flags = TaskFlags.RunOnlyIfLoggedOn
                                NewTask.SetAccountInformation(Environment.MachineName & "\" & Environment.UserName, Nothing)
                                NewTask.ApplicationName = Application.StartupPath & Path.DirectorySeparatorChar & "uaimage.exe"
                                NewTask.WorkingDirectory = Application.StartupPath
                                NewTask.Comment = "Auto Generated by Usage Agent Image"
                                NewTime = Now.AddMinutes(5)
                                NewTrigger = New DailyTrigger(CShort(NewTime.Hour), CShort(NewTime.Minute))
                                NewTrigger.DurationMinutes = 1440
                                NewTrigger.IntervalMinutes = CInt(NewConfigurationData.UpdateInterval)
                                NewTask.Triggers.Add(NewTrigger)
                                NewTask.Save()
                                NewTask.Dispose()

                                If NewConfigurationData.OffpeakStartHour <> "0" Or NewConfigurationData.OffpeakEndHour <> "0" Then
                                    'only add if not WAIX
                                    If NewConfigurationData.OffpeakStartHour <> NewConfigurationData.OffpeakEndHour Then
                                        'create tasks just before offpeak start time
                                        TaskCount += 1
                                        NewTask = NewScheduledTasks.CreateTask("UAImage " & TaskCount)
                                        NewTask.Flags = TaskFlags.RunOnlyIfLoggedOn
                                        NewTask.SetAccountInformation(Environment.MachineName & "\" & Environment.UserName, Nothing)
                                        NewTask.ApplicationName = Application.StartupPath & Path.DirectorySeparatorChar & "uaimage.exe"
                                        NewTask.WorkingDirectory = Application.StartupPath
                                        NewTask.Comment = "Auto Generated by Usage Agent Image"
                                        If NewConfigurationData.OffpeakStartHour = "0" Then
                                            StartHour = 23
                                        Else
                                            StartHour = CShort(Val(NewConfigurationData.OffpeakStartHour) - 1)
                                        End If
                                        NewTrigger = New DailyTrigger(StartHour, 59)
                                        NewTask.Triggers.Add(NewTrigger)
                                        NewTask.Save()
                                        NewTask.Dispose()

                                        'create tasks just before offpeak end time
                                        TaskCount += 1
                                        NewTask = NewScheduledTasks.CreateTask("UAImage " & TaskCount)
                                        NewTask.Flags = TaskFlags.RunOnlyIfLoggedOn
                                        NewTask.SetAccountInformation(Environment.MachineName & "\" & Environment.UserName, Nothing)
                                        NewTask.ApplicationName = Application.StartupPath & Path.DirectorySeparatorChar & "uaimage.exe"
                                        NewTask.WorkingDirectory = Application.StartupPath
                                        NewTask.Comment = "Auto Generated by Usage Agent Image"
                                        If NewConfigurationData.OffpeakEndHour = "0" Then
                                            StartHour = 23
                                        Else
                                            StartHour = CShort(Val(NewConfigurationData.OffpeakEndHour) - 1)
                                        End If
                                        NewTrigger = New DailyTrigger(StartHour, 59)
                                        NewTask.Triggers.Add(NewTrigger)
                                        NewTask.Save()
                                        NewTask.Dispose()
                                    End If
                                End If
                            End If
                        Catch ex As Exception
                        Finally
                            If NewScheduledTasks IsNot Nothing Then NewScheduledTasks.Dispose()
                        End Try
                    End If
                Else
                    'UNIX detected

                    'read crontab
                    Dim strCron As String = NewShell(AppDataPath, "crontab", "-l", True)

                    'split into lines
                    Dim strData() As String = strCron.Split(vbLf.ToCharArray)

                    'generate cron file
                    Using sw2 As New StreamWriter(AppDataPath & "crontab.txt")
                        'write all non UAWallpaper commands back to cron
                        For Each strCommand As String In strData
                            If strCommand.Trim.StartsWith("#") = False And strCommand.Trim <> "" Then
                                If strCommand.Contains("uawallpaper.exe") = False Then
                                    sw2.WriteLine(strCommand)
                                End If
                            End If
                        Next

                        'write back if enabled
                        Dim StartHour As Integer
                        If NewConfigurationData.WallpaperEnable = True And NewConfigurationData.WallpaperFormList.Count > 0 And NewConfigurationData.WallpaperUnixCommand <> "" Then
                            'create main wallpaper task
                            sw2.WriteLine("*/" & NewConfigurationData.UpdateInterval & " * * * * DISPLAY=:0.0 sh -c 'mono " & Application.StartupPath & "/uawallpaper.exe'")

                            If NewConfigurationData.OffpeakStartHour <> "0" Or NewConfigurationData.OffpeakEndHour <> "0" Then

                                'only add if not WAIX
                                If NewConfigurationData.OffpeakStartHour <> NewConfigurationData.OffpeakEndHour Then

                                    'create tasks just before offpeak start time
                                    If NewConfigurationData.OffpeakStartHour = "0" Then
                                        StartHour = 23
                                    Else
                                        StartHour = CShort(Val(NewConfigurationData.OffpeakStartHour) - 1)
                                    End If
                                    sw2.WriteLine("59 " & StartHour.ToString & " * * * DISPLAY=:0.0 sh -c 'mono " & Application.StartupPath & "/uawallpaper.exe'")

                                    'create tasks just before offpeak end time
                                    If NewConfigurationData.OffpeakEndHour = "0" Then
                                        StartHour = 23
                                    Else
                                        StartHour = CShort(Val(NewConfigurationData.OffpeakEndHour) - 1)
                                    End If
                                    sw2.WriteLine("59 " & StartHour.ToString & " * * * DISPLAY=:0.0 sh -c 'mono " & Application.StartupPath & "/uawallpaper.exe'")
                                End If
                            End If
                        End If

                        sw2.Close()
                    End Using

                    'set crontab
                    NewShell(Application.StartupPath, "crontab", AppDataPath & "crontab.txt", False)
                End If

            End If

            SaveConfiguration = True
        Catch ex As Exception
            MessageBox.Show(ex.ToString, "Usage Agent Configuration", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Function

    Sub AddShutdownScript(ByVal strScriptName As String, ByVal strRootPath As String, Optional ByVal strScriptParameters As String = "")
        'if script already exists then exit 
        If CheckShutdownScript(strScriptName, strRootPath, strScriptParameters) = True Then Exit Sub

        'set script to run on windows shutdown
        Dim RegKey As Microsoft.Win32.RegistryKey
        Dim KeyIndex As Integer
        Dim KeyHandle As Int32

        Try
            'create the shutdown key
            RegKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(strRootPath & "\Shutdown")

            'create the Startup key
            RegKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(strRootPath & "\Startup")

            'create policy 0 key
            RegKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(strRootPath & "\Shutdown\0")
            'create sub paramaters
            RegKey.SetValue("DisplayName", "Local Group Policy")
            RegKey.SetValue("FileSysPath", Environment.SystemDirectory & "\GroupPolicy\Machine")
            RegKey.SetValue("GPO-ID", "LocalGPO")
            RegKey.SetValue("GPOName", "Local Group Policy")
            RegKey.SetValue("SOM-ID", "Local")
            'get index of last entry
            KeyIndex = RegKey.SubKeyCount
            RegKey.Close()

            'create key 
            RegKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(strRootPath & "\Shutdown\0\" & KeyIndex)
            'create sub paramaters
            KeyHandle = 0
            RegOpenKey(HKEY_LOCAL_MACHINE, strRootPath & "\Shutdown\0\" & KeyIndex, KeyHandle)
            If KeyHandle <> 0 Then
                RegSetValueEx(KeyHandle, "ExecTime", 0&, REG_QWORD, Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0), 16)
                RegCloseKey(KeyHandle)
            End If
            RegKey.SetValue("Parameters", strScriptParameters)
            RegKey.SetValue("Script", strScriptName)
            RegKey.Close()

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Sub RemoveShutdownScript(ByVal strScriptName As String, ByVal strRootPath As String, Optional ByVal strScriptParameters As String = "")

        Dim RegKey As Microsoft.Win32.RegistryKey
        Dim SubRegKey As Microsoft.Win32.RegistryKey
        Dim NewSubRegKey As Microsoft.Win32.RegistryKey
        Dim KeyHandle As Int32
        Dim x As Integer
        Try
            'loop through all keys and remove where found
            RegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strRootPath & "\Shutdown\0", True)
            If RegKey IsNot Nothing Then
                'if there is only one entry Left, delete everything
                If RegKey.SubKeyCount = 1 Then
                    RegKey.Close()
                    RegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strRootPath & "\Shutdown", True)
                    RegKey.DeleteSubKeyTree("0")
                    RegKey.Close()
                    Exit Sub
                End If

                For x = 0 To RegKey.SubKeyCount - 1
                    SubRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strRootPath & "\Shutdown\0\" & x, False)
                    If Format(SubRegKey.GetValue("Script")) = strScriptName And Format(SubRegKey.GetValue("Parameters")) = strScriptParameters Then
                        'remove key
                        RegKey.DeleteSubKey(x.ToString)
                    End If
                    SubRegKey.Close()
                Next

                'write changes
                RegKey.Flush()

                'resort remaining keys
                Dim SubKeyNames() As String = RegKey.GetSubKeyNames
                For x = 0 To RegKey.SubKeyCount - 1
                    'check if name is correct
                    If Val(SubKeyNames(x)) <> x Then
                        'copy reg key
                        SubRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strRootPath & "\Shutdown\0\" & SubKeyNames(x), False)
                        RegKey.CreateSubKey(x.ToString)
                        NewSubRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strRootPath & "\Shutdown\0\" & x, True)

                        'copy values
                        KeyHandle = 0
                        RegOpenKey(HKEY_LOCAL_MACHINE, strRootPath & "\Shutdown\0\" & x, KeyHandle)
                        If KeyHandle <> 0 Then
                            RegSetValueEx(KeyHandle, "ExecTime", 0&, REG_QWORD, Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0) + Chr(0), 16)
                            RegCloseKey(KeyHandle)
                        End If
                        NewSubRegKey.SetValue("Parameters", SubRegKey.GetValue("Parameters"))
                        NewSubRegKey.SetValue("Script", SubRegKey.GetValue("Script"))
                        NewSubRegKey.Close()

                        SubRegKey.Close()

                        'delete reg key
                        RegKey.DeleteSubKey(SubKeyNames(x))
                    End If
                Next

                RegKey.Close()
            End If

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try

    End Sub

    Function CheckShutdownScript(ByVal strScriptName As String, ByVal strRootPath As String, Optional ByVal strScriptParameters As String = "") As Boolean
        CheckShutdownScript = False

        Dim RegKey As Microsoft.Win32.RegistryKey
        Dim SubRegKey As Microsoft.Win32.RegistryKey
        Dim x As Integer
        Try
            'check if key already exists
            RegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strRootPath & "\Shutdown\0", False)
            If RegKey IsNot Nothing Then
                For x = 0 To RegKey.SubKeyCount - 1
                    SubRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strRootPath & "\Shutdown\0\" & x, False)
                    If Format(SubRegKey.GetValue("Script")) = strScriptName And Format(SubRegKey.GetValue("Parameters")) = strScriptParameters Then
                        CheckShutdownScript = True
                        Exit Function
                    End If
                    SubRegKey.Close()
                Next
                RegKey.Close()
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try

    End Function

    Function KillProcess(ByVal ProcessName As String) As Boolean
        Dim intCount As Integer = 0
        Dim myProcesses As Process() = Process.GetProcessesByName(ProcessName)
        If myProcesses.Length > 0 Then
            'kill process
            intCount = 0
RetryKill:
            Try
                myProcesses(0).Kill()
            Catch ex As Exception
                intCount += 1
                If intCount > 10 Then
                    Return False
                Else
                    System.Threading.Thread.Sleep(1000)
                End If
                GoTo RetryKill
            End Try
        End If

        Return True

    End Function

    Function EncodeHexString(ByVal sText As String) As String
        Dim intLength As Integer = sText.Length
        If (intLength = 0) Then Return ""
        Dim intCount As Integer = 0
        Dim sb As New System.Text.StringBuilder(intLength * 2)
        Dim bBytes() As Byte = System.Text.Encoding.ASCII.GetBytes(sText)
        For intCount = 0 To bBytes.Length - 1
            If bBytes(intCount) < 48 Or (bBytes(intCount) > 57 And bBytes(intCount) < 65) Or (bBytes(intCount) > 90 And bBytes(intCount) < 97) Or bBytes(intCount) > 122 Then
                If bBytes(intCount) = 32 Then
                    'space
                    sb.Append("+")
                Else
                    sb.AppendFormat("%{0:X2}", bBytes(intCount))
                End If
            Else
                sb.Append(Chr(bBytes(intCount)))
            End If
        Next
        Return sb.ToString()
    End Function

    Function GetAppDataPath() As String
        If UnixDetected() = False Then
            'windows
            GetAppDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) & Path.DirectorySeparatorChar & "UsageAgent" & Path.DirectorySeparatorChar
        Else
            'unix
            GetAppDataPath = Application.StartupPath
            If GetAppDataPath.EndsWith(Path.DirectorySeparatorChar) = False Then GetAppDataPath &= Path.DirectorySeparatorChar
        End If
    End Function

    Function TestIsNumeric(ByVal strValue As String) As Boolean
        TestIsNumeric = False

        If strValue = "0" Then
            TestIsNumeric = True
            Exit Function
        End If

        Dim strTemp As String = Format(Val(strValue))

        If strValue = strTemp Then
            TestIsNumeric = True
            Exit Function
        End If
    End Function

    Function NewShell(ByVal strWorkingDirectory As String, ByVal strFileName As String, ByVal strArguments As String, ByVal strWait As Boolean, Optional ByRef runElevated As Boolean = False) As String
        Try
            Dim NewProcess As New System.Diagnostics.Process
            NewProcess.StartInfo.WorkingDirectory = strWorkingDirectory
            NewProcess.StartInfo.CreateNoWindow = True
            NewProcess.StartInfo.FileName = strFileName
            NewProcess.StartInfo.Arguments = strArguments
            NewProcess.StartInfo.UseShellExecute = False
            If (runElevated) Then
                NewProcess.StartInfo.Verb = "runas"
                NewProcess.StartInfo.UseShellExecute = True
            Else
                NewProcess.StartInfo.RedirectStandardOutput = True
            End If
            NewProcess.Start()
            If strWait = True Then
                NewShell = NewProcess.StandardOutput.ReadToEnd()
                NewProcess.WaitForExit()
            Else
                NewShell = ""
            End If
            NewProcess.Dispose()
        Catch ex As Exception
            MessageBox.Show(ex.ToString, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Function

    Function GetElementsByTagName(ByVal doc As XmlDocument, ByVal TagName As String) As String
        Dim root As XmlNodeList
        root = doc.GetElementsByTagName(TagName)
        If root.Count > 0 Then
            GetElementsByTagName = root(0).InnerText
        Else
            GetElementsByTagName = Nothing
        End If
    End Function

    Function SendMail(ByVal MailServer As String, ByVal EmailAddress As String, ByVal EmailSubject As String, ByVal EmailMessage As String, Optional ByVal bolTestEmail As Boolean = False) As Boolean
        SendMail = False
        Try
            Dim MailFrom As New EmailAddress("UsageAgent@YourPC.com", "UsageAgent")
            Dim MailTo As New EmailAddress(EmailAddress)

            Dim MailMsg As New MailMessage(MailFrom, MailTo)

            MailMsg.Subject = EmailSubject
            MailMsg.Body = EmailMessage

            ' mail message properties
            MailMsg.Charset = "ISO-8859-1"

            If bolTestEmail = False Then
                MailMsg.HtmlBody = My.Computer.FileSystem.ReadAllText(Application.StartupPath & Path.DirectorySeparatorChar & "mail.htm", System.Text.Encoding.ASCII)
                MailMsg.HtmlBody = Replace(MailMsg.HtmlBody, "<InsertMessageHere>", EmailMessage)

                MailMsg.Priority = MailPriority.High

                ' add images
                MailMsg.AddImage(Application.StartupPath & Path.DirectorySeparatorChar & "n.png", "n")
                MailMsg.AddImage(Application.StartupPath & Path.DirectorySeparatorChar & "s.png", "s")
                MailMsg.AddImage(Application.StartupPath & Path.DirectorySeparatorChar & "e.png", "e")
                MailMsg.AddImage(Application.StartupPath & Path.DirectorySeparatorChar & "w.png", "w")
                MailMsg.AddImage(AppDataPath & "uaimage.png", "UAImage")
            End If

            Dim SMTPServer As New Smtp(MailServer, 25)
            SMTPServer.SendMail(MailMsg)

            SendMail = True
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Function

    Function IsValidEmail(ByVal EmailAddress As String) As Boolean
        IsValidEmail = True
        Dim regValidEmail As New System.Text.RegularExpressions.Regex("^((?>[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+\x20*|""((?=[\x01-\x7f])[^""\\]|\\[\x01-\x7f])*""\x20*)*(?<angle><))?((?!\.)(?>\.?[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+)+|""((?=[\x01-\x7f])[^""\\]|\\[\x01-\x7f])*"")@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$")
        If Not regValidEmail.IsMatch(EmailAddress) Then IsValidEmail = False
    End Function

    Sub SetDefaultAlertValue(ByVal lstAlert As ListBox)
        lstAlert.Items.Clear()
        lstAlert.Items.Add("80%")
        lstAlert.Items.Add("100%")
    End Sub

    Sub AlertSort(ByRef DataList As ListBox)
        Dim intX As Integer
        Dim strSwap As String
        Dim blnSwapped As Boolean = True

        Do While blnSwapped
            blnSwapped = False
            For intX = 0 To DataList.Items.Count - 2
                If Val(DataList.Items(intX)) > Val(DataList.Items(intX + 1)) Then
                    strSwap = DataList.Items(intX).ToString
                    DataList.Items(intX) = DataList.Items(intX + 1)
                    DataList.Items(intX + 1) = strSwap
                    blnSwapped = True
                End If
            Next
        Loop
    End Sub

    Sub CreateImageFile(ByVal NewConfigurationData As ConfigurationData, ByVal ISPReturnData As ISPReturnData)
        'get form size
        Dim FormSize As Point = CalculateFormSize(NewConfigurationData, ISPReturnData)

        'create bitmap
        Dim UABitmap As New Bitmap(FormSize.X, FormSize.Y)

        'draw ISP form
        DrawISPForm(UABitmap, ISPReturnData, NewConfigurationData)

        'save bitmap
        UABitmap.Save(AppDataPath & "uaimage.png", System.Drawing.Imaging.ImageFormat.Png)

        'clean up
        UABitmap.Dispose()
    End Sub

    Sub ProcessISPData(ByVal ConfigurationData As ConfigurationData, ByVal ISPReturnData As ISPReturnData)

        'validate dates
        If Date.Compare(ISPReturnData.RolloverDate, ISPReturnData.LastUpdated) > 0 Then
            ISPReturnData.ErrorMessage = "Start Month is after Last Updated"
        End If

        'Console.WriteLine(Format(ISPReturnData.LastUpdated, "dd.MM.yyyy"))
        'Console.WriteLine(Format(ISPReturnData.RolloverDate.AddMonths(1), "dd.MM.yyyy"))

        If Date.Compare(ISPReturnData.LastUpdated, ISPReturnData.RolloverDate.AddMonths(1)) > 0 Then
            ISPReturnData.ErrorMessage = "Last Updated is after End of Month"
        End If

        If ISPReturnData.LastUpdated = Nothing Or IsDate(ISPReturnData.LastUpdated) = False Then
            ISPReturnData.ErrorMessage = ISPReturnData.LastUpdated & " - Invalid Last Updated"
        End If

        'check for error
        If ISPReturnData.ErrorMessage <> "" Then Exit Sub

        '#################################################################

        'create ISP stats

        'round off values to nearest mb
        If ISPReturnData.PeakDownload > 0 Then ISPReturnData.PeakDownload = CSng(CInt(ISPReturnData.PeakDownload))
        If ISPReturnData.PeakUpload > 0 Then ISPReturnData.PeakUpload = CSng(CInt(ISPReturnData.PeakUpload))
        If ISPReturnData.OffpeakDownload > 0 Then ISPReturnData.OffpeakDownload = CSng(CInt(ISPReturnData.OffpeakDownload))
        If ISPReturnData.OffpeakUpload > 0 Then ISPReturnData.OffpeakUpload = CSng(CInt(ISPReturnData.OffpeakUpload))

        Dim HourOffset As Integer = 0
        If ConfigurationData.OffpeakTimeZone = "Sydney" Then
            Dim CurrentTime As DateTime = DateTime.Now
            Dim nowGMT As DateTime = CurrentTime.ToUniversalTime()
            Dim diff As TimeSpan = CurrentTime.Subtract(nowGMT)
            HourOffset = 10 - CInt(diff.TotalHours)

            'check for daylight savings
            Dim OldYear As Integer = CurrentTime.Year
            If Now.Month >= 1 And Now.Month <= 9 Then OldYear -= 1
            Dim NewYear As Integer = OldYear + 1

            If CurrentTime >= Date.ParseExact("28/10/" & OldYear, "dd/MM/yyyy", Nothing) And CurrentTime <= Date.ParseExact("06/04/" & NewYear, "dd/MM/yyyy", Nothing) Then HourOffset += 1
        End If

        Dim CurrentHour As Integer = CInt(Math.Floor(Now.Hour + HourOffset))
        If CurrentHour >= 24 Then CurrentHour -= 24

        ISPReturnData.DaysUsed = CSng(CInt(System.DateTime.op_Subtraction(Now, ISPReturnData.RolloverDate).TotalHours / 24 * 10) / 10)
        ISPReturnData.DaysLeft = CSng(CInt(System.DateTime.op_Subtraction(ISPReturnData.RolloverDate.AddMonths(1), Now).TotalHours / 24 * 10) / 10)

        'on last day, round to one
        If ISPReturnData.DaysLeft < 1 Then
            ISPReturnData.DaysLeft = 1
            ISPReturnData.DaysUsed = CSng(CInt(ISPReturnData.DaysUsed))
        End If

        'check if not unlimited
        If Val(ConfigurationData.PeakUsageLimit) > 0 Then
            If ConfigurationData.UploadCounted = False Then
                If ISPReturnData.PeakDownload > Val(ConfigurationData.PeakUsageLimit) Then
                    ISPReturnData.PeakUsageValue = (ISPReturnData.PeakDownload / CSng(Val(ConfigurationData.PeakUsageLimit))) * 100
                    If ISPReturnData.PeakUsageValue > 32767 Then ISPReturnData.PeakUsageValue = 32767
                    ISPReturnData.PeakUsageRemainingDescription = "0 MB"
                    ISPReturnData.PeakUsageAverageDescription = "0 MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                    ISPReturnData.PeakUsageRemainingPerDayDescription = "0 MB/Day (" & ISPReturnData.DaysLeft & " Days)"
                    ISPReturnData.PeakShaped = True
                Else
                    ISPReturnData.PeakUsageValue = (ISPReturnData.PeakDownload / CSng(Val(ConfigurationData.PeakUsageLimit))) * 100
                    If ISPReturnData.DaysUsed > 0 Then
                        ISPReturnData.UsageDeltaValue = CSng(CInt((CSng(Val(ConfigurationData.PeakUsageLimit)) / ISPReturnData.DaysUsed) - ISPReturnData.PeakUsageValue))
                    End If
                    ISPReturnData.UsageDeltaDescription = ISPReturnData.UsageDeltaValue.ToString & " MB"
                    ISPReturnData.PeakUsageRemainingDescription = (Val(ConfigurationData.PeakUsageLimit) - ISPReturnData.PeakDownload).ToString & " MB"
                    If ISPReturnData.DaysUsed < 1 Then
                        ISPReturnData.PeakUsageAverageDescription = "Not Available"
                    Else
                        ISPReturnData.PeakUsageAverageDescription = CInt((Val(ConfigurationData.PeakUsageLimit) / (ISPReturnData.DaysUsed))) & " MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                    End If
                    If ISPReturnData.DaysLeft < 1 Then
                        ISPReturnData.PeakUsageRemainingPerDayDescription = ISPReturnData.PeakUsageRemainingDescription & "/Day (" & ISPReturnData.DaysLeft & " Days)"
                    Else
                        ISPReturnData.PeakUsageRemainingPerDayDescription = (CInt((Val(ConfigurationData.PeakUsageLimit) - ISPReturnData.PeakDownload) / ISPReturnData.DaysLeft)) & " MB/Day (" & ISPReturnData.DaysLeft & " Days)"
                    End If
                    ISPReturnData.PeakShaped = False
                End If
            Else
                If (ISPReturnData.PeakDownload + ISPReturnData.PeakUpload) > Val(ConfigurationData.PeakUsageLimit) Then
                    ISPReturnData.PeakUsageValue = ((ISPReturnData.PeakDownload + ISPReturnData.PeakUpload) / CSng(Val(ConfigurationData.PeakUsageLimit))) * 100
                    If ISPReturnData.PeakUsageValue > 32767 Then ISPReturnData.PeakUsageValue = 32767
                    ISPReturnData.PeakUsageRemainingDescription = "0 MB"
                    ISPReturnData.PeakUsageAverageDescription = "0 MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                    ISPReturnData.PeakUsageRemainingPerDayDescription = "0 MB/Day (" & ISPReturnData.DaysLeft & " Days)"
                    ISPReturnData.PeakShaped = True
                Else
                    ISPReturnData.PeakUsageValue = ((ISPReturnData.PeakDownload + ISPReturnData.PeakUpload) / CSng(Val(ConfigurationData.PeakUsageLimit))) * 100
                    ISPReturnData.PeakUsageRemainingDescription = (Val(ConfigurationData.PeakUsageLimit) - (ISPReturnData.PeakDownload + ISPReturnData.PeakUpload)).ToString & " MB"

                    If ISPReturnData.DaysUsed = 0 Then
                        ISPReturnData.PeakUsageAverageDescription = "Not Available"
                    Else
                        ISPReturnData.UsageDeltaValue = CSng(CInt((ISPReturnData.PeakDownload + ISPReturnData.PeakUpload) - (CSng(Val(ConfigurationData.PeakUsageLimit)) / (ISPReturnData.DaysUsed + ISPReturnData.DaysLeft) * ISPReturnData.DaysUsed)))
                        If (ISPReturnData.UsageDeltaValue > 0) Then
                            ISPReturnData.UsageDeltaDescription = "+"
                        End If
                        ISPReturnData.UsageDeltaDescription &= ISPReturnData.UsageDeltaValue.ToString & " MB"
                        ISPReturnData.PeakUsageAverageDescription = CInt((Val(ConfigurationData.PeakUsageLimit) / (ISPReturnData.DaysUsed))) & " MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                    End If
                    If ISPReturnData.DaysLeft > 0 Then
                        ISPReturnData.PeakUsageRemainingPerDayDescription = (CInt((Val(ConfigurationData.PeakUsageLimit) - (ISPReturnData.PeakDownload + ISPReturnData.PeakUpload)) / ISPReturnData.DaysLeft)) & " MB/Day (" & ISPReturnData.DaysLeft & " Days)"
                    Else
                        ISPReturnData.PeakUsageRemainingPerDayDescription = (CInt((Val(ConfigurationData.PeakUsageLimit) - (ISPReturnData.PeakDownload + ISPReturnData.PeakUpload)))) & " MB/Day (" & ISPReturnData.DaysLeft & " Days)"
                    End If
                    ISPReturnData.PeakShaped = False
                End If
            End If
        Else
            'unlimited
            ISPReturnData.PeakUsageRemainingDescription = "Unlimited"
        End If

        'do calculations on offpeak
        If ConfigurationData.OffpeakAvailable = True Then

            'check if not unlimited
            If ConfigurationData.OffpeakUnlimited = False Then
                Dim DaysLeftOffpeak As Single = ISPReturnData.DaysLeft
                If CurrentHour >= CInt(Val(ConfigurationData.OffpeakEndHour)) Then DaysLeftOffpeak -= 1
                If DaysLeftOffpeak < 0 Then DaysLeftOffpeak = 0

                If ConfigurationData.UploadCounted = False Then
                    If ISPReturnData.OffpeakDownload > Val(ConfigurationData.OffpeakUsageLimit) Then
                        ISPReturnData.OffpeakUsageValue = (ISPReturnData.OffpeakDownload / CSng(Val(ConfigurationData.OffpeakUsageLimit))) * 100
                        If ISPReturnData.OffpeakUsageValue > 32767 Then ISPReturnData.OffpeakUsageValue = 32767
                        ISPReturnData.OffpeakUsageRemainingDescription = "0 MB"
                        ISPReturnData.OffpeakUsageAverageDescription = "0 MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                        ISPReturnData.OffpeakUsageRemainingPerDayDescription = "0 MB/Day (" & DaysLeftOffpeak & " Days)"
                        ISPReturnData.OffpeakShaped = True
                    Else
                        ISPReturnData.OffpeakUsageValue = (ISPReturnData.OffpeakDownload / CSng(Val(ConfigurationData.OffpeakUsageLimit))) * 100
                        ISPReturnData.OffpeakUsageRemainingDescription = (Val(ConfigurationData.OffpeakUsageLimit) - ISPReturnData.OffpeakDownload).ToString & " MB"
                        If ISPReturnData.DaysUsed < 1 Then
                            ISPReturnData.PeakUsageAverageDescription = "Not Available"
                        Else
                            ISPReturnData.OffpeakUsageAverageDescription = CInt((ISPReturnData.OffpeakDownload / (ISPReturnData.DaysUsed))) & " MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                        End If
                        If DaysLeftOffpeak < 1 Then
                            ISPReturnData.OffpeakUsageRemainingPerDayDescription = (CInt((Val(ConfigurationData.OffpeakUsageLimit) - ISPReturnData.OffpeakDownload))) & " MB/Day (" & DaysLeftOffpeak & " Days)"
                        Else
                            ISPReturnData.OffpeakUsageRemainingPerDayDescription = (CInt((Val(ConfigurationData.OffpeakUsageLimit) - ISPReturnData.OffpeakDownload) / DaysLeftOffpeak)) & " MB/Day (" & DaysLeftOffpeak & " Days)"
                        End If
                        ISPReturnData.OffpeakShaped = False
                    End If
                Else
                    If (ISPReturnData.OffpeakDownload + ISPReturnData.OffpeakUpload) > Val(ConfigurationData.OffpeakUsageLimit) Then
                        ISPReturnData.OffpeakUsageValue = ((ISPReturnData.OffpeakDownload + ISPReturnData.OffpeakUpload) / CSng(Val(ConfigurationData.OffpeakUsageLimit))) * 100
                        If ISPReturnData.OffpeakUsageValue > 32767 Then ISPReturnData.OffpeakUsageValue = 32767
                        ISPReturnData.OffpeakUsageRemainingDescription = "0 MB"
                        ISPReturnData.OffpeakUsageAverageDescription = "0 MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                        ISPReturnData.OffpeakUsageRemainingPerDayDescription = "0 MB/Day (" & DaysLeftOffpeak & " Days)"
                        ISPReturnData.OffpeakShaped = True
                    Else
                        ISPReturnData.OffpeakUsageValue = ((ISPReturnData.OffpeakDownload + ISPReturnData.OffpeakUpload) / CSng(Val(ConfigurationData.OffpeakUsageLimit))) * 100
                        ISPReturnData.OffpeakUsageRemainingDescription = (Val(ConfigurationData.OffpeakUsageLimit) - (ISPReturnData.OffpeakDownload + ISPReturnData.OffpeakUpload)).ToString & " MB"
                        If ISPReturnData.DaysUsed < 1 Then
                            ISPReturnData.PeakUsageAverageDescription = "Not Available"
                        Else
                            ISPReturnData.OffpeakUsageAverageDescription = CInt(((ISPReturnData.OffpeakDownload + ISPReturnData.OffpeakUpload) / (ISPReturnData.DaysUsed))) & " MB/Day (" & ISPReturnData.DaysUsed & " Days)"
                        End If
                        If DaysLeftOffpeak < 1 Then
                            ISPReturnData.OffpeakUsageRemainingPerDayDescription = (CInt((Val(ConfigurationData.OffpeakUsageLimit) - (ISPReturnData.OffpeakDownload + ISPReturnData.OffpeakUpload)))) & " MB/Day (" & DaysLeftOffpeak & " Days)"
                        Else
                            ISPReturnData.OffpeakUsageRemainingPerDayDescription = (CInt((Val(ConfigurationData.OffpeakUsageLimit) - (ISPReturnData.OffpeakDownload + ISPReturnData.OffpeakUpload)) / DaysLeftOffpeak)) & " MB/Day (" & DaysLeftOffpeak & " Days)"
                        End If
                        ISPReturnData.OffpeakShaped = False
                    End If
                End If
            End If

            'restore calculation
            ISPReturnData.DaysUsed = CSng(CInt(System.DateTime.op_Subtraction(Now, ISPReturnData.RolloverDate).TotalHours / 24 * 10) / 10)
            ISPReturnData.DaysLeft = CSng(CInt(System.DateTime.op_Subtraction(ISPReturnData.RolloverDate.AddMonths(1), Now).TotalHours / 24 * 10) / 10)

            'check if we are in off peak time
            If Val(ConfigurationData.OffpeakStartHour) = Val(ConfigurationData.OffpeakEndHour) Then
                'waix
                ISPReturnData.OffpeakNow = False
            Else
                If ConfigurationData.OffpeakWeekendsUnlimited = True And (Now.DayOfWeek = DayOfWeek.Saturday Or Now.DayOfWeek = DayOfWeek.Sunday) Then
                    ISPReturnData.PeakNow = False
                    ISPReturnData.OffpeakNow = True
                Else
                    If Val(ConfigurationData.OffpeakStartHour) < Val(ConfigurationData.OffpeakEndHour) Then
                        If CurrentHour >= Val(ConfigurationData.OffpeakStartHour) And CurrentHour < Val(ConfigurationData.OffpeakEndHour) Then
                            If ConfigurationData.OffpeakUnlimited = True Then
                                'unlimited
                                ISPReturnData.PeakNow = False
                                ISPReturnData.OffpeakNow = True
                            Else
                                'we've gone over our offpeak allotment and are into peak time
                                If ConfigurationData.OffpeakReached = "Usage taken from Peak" And ISPReturnData.OffpeakDownload >= Val(ConfigurationData.OffpeakUsageLimit) Then
                                    ISPReturnData.OffpeakNow = False
                                Else
                                    ISPReturnData.PeakNow = False
                                    ISPReturnData.OffpeakNow = True
                                End If
                            End If
                        Else
                            ISPReturnData.OffpeakNow = False
                        End If
                    Else
                        If CurrentHour >= Val(ConfigurationData.OffpeakStartHour) Or CurrentHour < Val(ConfigurationData.OffpeakEndHour) Then
                            If ConfigurationData.OffpeakUnlimited = True Then
                                'unlimited
                                ISPReturnData.PeakNow = False
                                ISPReturnData.OffpeakNow = True
                            Else
                                'we've gone over our offpeak allotment and are into peak time
                                If ConfigurationData.OffpeakReached = "Usage taken from Peak" And ISPReturnData.OffpeakDownload >= Val(ConfigurationData.OffpeakUsageLimit) Then
                                    ISPReturnData.OffpeakNow = False
                                Else
                                    ISPReturnData.PeakNow = False
                                    ISPReturnData.OffpeakNow = True
                                End If
                            End If
                        Else
                            ISPReturnData.OffpeakNow = False
                        End If
                    End If
                End If
            End If
        Else
            'unlimited
            ISPReturnData.OffpeakUsageRemainingDescription = "Unlimited"
        End If

        If ConfigurationData.PeakReached = "Shaped" Then
            If ISPReturnData.OffpeakNow = False Then
                If ISPReturnData.PeakShaped = True Then
                    ISPReturnData.ShapedNow = True
                Else
                    ISPReturnData.ShapedNow = False
                End If
            Else
                If ISPReturnData.OffpeakShaped = True Then
                    ISPReturnData.ShapedNow = True
                Else
                    ISPReturnData.ShapedNow = False
                End If
            End If
        End If

    End Sub

    Sub ProcessAlerts(ByVal ConfigurationData As ConfigurationData, ByVal ISPReturnData As ISPReturnData)
        If ConfigurationData.AlertEnable = True Then
            Dim Subject As String
            Dim Message As String
            Dim Count As Integer

            For Each strUsageValue As String In ConfigurationData.AlertValue.Items
                Count += 1

                'Alert1 = peak
                If Math.Floor(CInt(ISPReturnData.PeakUsageValue)) >= CInt(Val(strUsageValue)) Then
                    If ConfigurationData.Alert1Count < Count Then
                        ConfigurationData.Alert1Count += 1

                        'create image
                        CreateImageFile(ConfigurationData, ISPReturnData)

                        Subject = "You've used " & strUsageValue & " of your peak data allowance."
                        Message = "You've reached " & strUsageValue & " of your maximum peak data allowance for this month."
                        If ConfigurationData.AlertDialog = True Then
                            Dim NewfrmMessage As New frmMessage
                            NewfrmMessage.lblMessage.Text = Message
                            NewfrmMessage.ShowDialog()
                        End If
                        If ConfigurationData.AlertEmail = True Then SendMail(ConfigurationData.AlertMailServer, ConfigurationData.AlertMailTo, Subject, Message)
                    End If
                End If

                If ConfigurationData.OffpeakAvailable = True Then
                    'Alert2 = offpeak
                    If Math.Floor(CInt(ISPReturnData.OffpeakUsageValue)) >= CInt(Val(strUsageValue)) Then
                        If ConfigurationData.Alert2Count < Count Then
                            ConfigurationData.Alert2Count += 1

                            'create image
                            CreateImageFile(ConfigurationData, ISPReturnData)

                            Subject = "You've used " & strUsageValue & " of your offpeak data allowance."
                            Message = "You've reached " & strUsageValue & " of your maximum offpeak data allowance for this month."
                            If ConfigurationData.AlertDialog = True Then
                                Dim NewfrmMessage As New frmMessage
                                NewfrmMessage.lblMessage.Text = Message
                                NewfrmMessage.ShowDialog()
                            End If
                            If ConfigurationData.AlertEmail = True Then SendMail(ConfigurationData.AlertMailServer, ConfigurationData.AlertMailTo, Subject, Message)
                        End If
                    End If
                End If
            Next
        End If

    End Sub

    Sub SetRolloverDate(ByVal ConfigurationData As ConfigurationData, ByVal ISPReturnData As ISPReturnData)
        'set rollover date
        Dim rollOverDate As DateTime = New DateTime(DateTime.Now.Year, DateTime.Now.Month, CInt(ConfigurationData.RolloverDay))

        If Val(ConfigurationData.RolloverDay) > Now.Date.Day Then
            rollOverDate = rollOverDate.AddMonths(-1)
        End If

        ISPReturnData.RolloverDate = rollOverDate
    End Sub
End Module

